nfs-ganesha 1.4

cidr_inaddr.c

Go to the documentation of this file.
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 }