nfs-ganesha 1.4
|
00001 /* 00002 * Functions to convert to/from in[6]_addr structs 00003 */ 00004 #ifdef HAVE_CONFIG_H 00005 #include "config.h" 00006 #endif 00007 00008 #include <errno.h> 00009 #include <stdlib.h> 00010 #include <string.h> 00011 #include "abstract_mem.h" 00012 #include "cidr.h" 00013 00014 00015 /* Create a struct in_addr with the given v4 address */ 00016 struct in_addr * 00017 cidr_to_inaddr(const CIDR *addr, struct in_addr *uptr) 00018 { 00019 struct in_addr *toret; 00020 00021 if(addr==NULL) 00022 { 00023 errno = EFAULT; 00024 return(NULL); 00025 } 00026 00027 /* Better be a v4 address... */ 00028 if(addr->proto != CIDR_IPV4) 00029 { 00030 errno = EPROTOTYPE; 00031 return(NULL); 00032 } 00033 00034 /* 00035 * Use the user's struct if possible, otherwise allocate one. It's 00036 * _their_ responsibility to give us the right type of struct to not 00037 * stomp all over the address space... 00038 */ 00039 toret = uptr; 00040 if(toret==NULL) 00041 toret = gsh_malloc(sizeof(struct in_addr)); 00042 if(toret==NULL) 00043 { 00044 errno = ENOMEM; 00045 return(NULL); 00046 } 00047 memset(toret, 0, sizeof(struct in_addr)); 00048 00049 /* Add 'em up and stuff 'em in */ 00050 toret->s_addr = ((addr->addr)[12] << 24) 00051 + ((addr->addr)[13] << 16) 00052 + ((addr->addr)[14] << 8) 00053 + ((addr->addr)[15]); 00054 00055 /* 00056 * in_addr's are USUALLY used inside sockaddr_in's to do socket 00057 * stuff. The upshot of this is that they generally need to be in 00058 * network byte order. We'll do that transition here; if the user 00059 * wants to be different, they'll have to manually convert. 00060 */ 00061 toret->s_addr = htonl(toret->s_addr); 00062 00063 return(toret); 00064 } 00065 00066 00067 /* Build up a CIDR struct from a given in_addr */ 00068 CIDR * 00069 cidr_from_inaddr(const struct in_addr *uaddr) 00070 { 00071 int i; 00072 CIDR *toret; 00073 in_addr_t taddr; 00074 00075 if(uaddr==NULL) 00076 { 00077 errno = EFAULT; 00078 return(NULL); 00079 } 00080 00081 toret = cidr_alloc(); 00082 if(toret==NULL) 00083 return(NULL); /* Preserve errno */ 00084 toret->proto = CIDR_IPV4; 00085 00086 /* 00087 * For IPv4, pretty straightforward, except that we need to jump 00088 * through a temp variable to convert into host byte order. 00089 */ 00090 taddr = ntohl(uaddr->s_addr); 00091 00092 /* Mask these just to be safe */ 00093 toret->addr[15] = (taddr & 0xff); 00094 toret->addr[14] = ((taddr>>8) & 0xff); 00095 toret->addr[13] = ((taddr>>16) & 0xff); 00096 toret->addr[12] = ((taddr>>24) & 0xff); 00097 00098 /* Give it a single-host mask */ 00099 toret->mask[15] = toret->mask[14] = 00100 toret->mask[13] = toret->mask[12] = 0xff; 00101 00102 /* Standard v4 overrides of addr and mask for mapped form */ 00103 for(i=0 ; i<=9 ; i++) 00104 toret->addr[i] = 0; 00105 for(i=10 ; i<=11 ; i++) 00106 toret->addr[i] = 0xff; 00107 for(i=0 ; i<=11 ; i++) 00108 toret->mask[i] = 0xff; 00109 00110 /* That's it */ 00111 return(toret); 00112 } 00113 00114 00115 /* Create a struct in5_addr with the given v6 address */ 00116 struct in6_addr * 00117 cidr_to_in6addr(const CIDR *addr, struct in6_addr *uptr) 00118 { 00119 struct in6_addr *toret; 00120 int i; 00121 00122 if(addr==NULL) 00123 { 00124 errno = EFAULT; 00125 return(NULL); 00126 } 00127 00128 /* 00129 * Note: We're allowing BOTH IPv4 and IPv6 addresses to go through 00130 * this function. The reason is that this allows us to build up an 00131 * in6_addr struct to be used to connect to a v4 host (via a 00132 * v4-mapped address) through a v6 socket connection. A v4 00133 * cidr_address, when built, has the upper bits of the address set 00134 * correctly for this to work. We don't support "compat"-mode 00135 * addresses here, though, and won't. 00136 */ 00137 if(addr->proto!=CIDR_IPV6 && addr->proto!=CIDR_IPV4) 00138 { 00139 errno = EPROTOTYPE; 00140 return(NULL); 00141 } 00142 00143 /* Use their struct if they gave us one */ 00144 toret = uptr; 00145 if(toret==NULL) 00146 toret = gsh_malloc(sizeof(struct in6_addr)); 00147 if(toret==NULL) 00148 { 00149 errno = ENOMEM; 00150 return(NULL); 00151 } 00152 memset(toret, 0, sizeof(struct in6_addr)); 00153 00154 /* 00155 * The in6_addr is defined to store it in 16 octets, just like we do. 00156 * But just to be safe, we're not going to stuff a giant copy in. 00157 * Most systems also use some union trickery to force alignment, but 00158 * we don't need to worry about that. 00159 * Now, this is defined to be in network byte order, which is 00160 * MSB-first. Since this is a structure of bytes, and we're filling 00161 * them in from the MSB onward ourself, we don't actually have to do 00162 * any conversions. 00163 */ 00164 for(i=0 ; i<=15 ; i++) 00165 toret->s6_addr[i] = addr->addr[i]; 00166 00167 return(toret); 00168 } 00169 00170 00171 /* And create up a CIDR struct from a given in6_addr */ 00172 CIDR * 00173 cidr_from_in6addr(const struct in6_addr *uaddr) 00174 { 00175 int i; 00176 CIDR *toret; 00177 00178 if(uaddr==NULL) 00179 { 00180 errno = EFAULT; 00181 return(NULL); 00182 } 00183 00184 toret = cidr_alloc(); 00185 if(toret==NULL) 00186 return(NULL); /* Preserve errno */ 00187 toret->proto = CIDR_IPV6; 00188 00189 /* 00190 * For v6, just iterate over the arrays and return. Set all 1's in 00191 * the mask while we're at it, since this is a single host. 00192 */ 00193 for(i=0 ; i<=15 ; i++) 00194 { 00195 toret->addr[i] = uaddr->s6_addr[i]; 00196 toret->mask[i] = 0xff; 00197 } 00198 00199 return(toret); 00200 }