nfs-ganesha 1.4

cidr_net.c

Go to the documentation of this file.
00001 /*
00002  * Functions to generate various networks based on a CIDR
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 
00012 #include "cidr.h"
00013 #include "abstract_mem.h"
00014 
00015 
00016 /* Get the CIDR's immediate supernet */
00017 CIDR *
00018 cidr_net_supernet(const CIDR *addr)
00019 {
00020         int i, j;
00021         int pflen;
00022         CIDR *toret;
00023 
00024         /* Quick check */
00025         if(addr==NULL)
00026         {
00027                 errno = EFAULT;
00028                 return(NULL);
00029         }
00030         
00031         /* If it's already a /0 in its protocol, return nothing */
00032         pflen = cidr_get_pflen(addr);
00033         if(pflen==0)
00034         {
00035                 errno = 0;
00036                 return(NULL);
00037         }
00038         
00039         toret = cidr_dup(addr);
00040         if(toret==NULL)
00041                 return(NULL); /* Preserve errno */
00042         
00043         /* Chop a bit off the netmask */
00044         /* This gets the last network bit */
00045         if(toret->proto==CIDR_IPV4)
00046                 pflen += 96;
00047         pflen--;
00048         i = pflen / 8;
00049         j = 7 - (pflen % 8);
00050 
00051         /* Make that bit a host bit */
00052         (toret->mask)[i] &= ~(1<<j);
00053 
00054         /*
00055          * Now zero out the host bits in the addr.  Do this manually instead
00056          * of calling cidr_addr_network() to save some extra copies and
00057          * allocationss and so forth.
00058          */
00059         for(/* i */ ; i<=15 ; i++)
00060         {
00061                 for(/* j */ ; j>=0 ; j--)
00062                         (toret->addr)[i] &= ~(1<<j);
00063                 j=7;
00064         }
00065 
00066         /* And send it back */
00067         return(toret);
00068 }
00069 
00070 
00071 /* Get the CIDR's two children */
00072 CIDR **
00073 cidr_net_subnets(const CIDR *addr)
00074 {
00075         int i, j;
00076         int pflen;
00077         CIDR **toret;
00078 
00079         if(addr==NULL)
00080         {
00081                 errno = EFAULT;
00082                 return(NULL);
00083         }
00084         
00085         /* You can't split a host address! */
00086         pflen = cidr_get_pflen(addr);
00087         if(  (addr->proto==CIDR_IPV4 && pflen==32)
00088           || (addr->proto==CIDR_IPV6 && pflen==128))
00089         {
00090                 errno = 0;
00091                 return(NULL);
00092         }
00093 
00094         toret = gsh_calloc(2, sizeof(CIDR *));
00095         if(toret==NULL)
00096         {
00097                 errno = ENOMEM;
00098                 return(NULL);
00099         }
00100         
00101         /* Get a blank-ish slate for the first kid */
00102         toret[0] = cidr_addr_network(addr);
00103         if(toret[0]==NULL)
00104         {
00105                 gsh_free(toret);
00106                 return(NULL); /* Preserve errno */
00107         }
00108 
00109         /* Find its first host bit */
00110         if(toret[0]->proto==CIDR_IPV4)
00111                 pflen += 96;
00112         i = pflen / 8;
00113         j = 7 - (pflen % 8);
00114 
00115         /* Make it a network bit */
00116         (toret[0])->mask[i] |= 1<<j;
00117 
00118         /* Now dup the second kid off that */
00119         toret[1] = cidr_dup(toret[0]);
00120         if(toret[1]==NULL)
00121         {
00122                 cidr_free(toret[0]);
00123                 gsh_free(toret);
00124                 return(NULL); /* Preserve errno */
00125         }
00126 
00127         /* And set that first host bit */
00128         (toret[1])->addr[i] |= 1<<j;
00129 
00130 
00131         /* Return the pair */
00132         return(toret);
00133 }