dhcp4_lease.c

00001 /* dhcp4_lease.c
00002  *
00003  * Convert the ISC dhcp lease options into libdhcp option tree
00004  *
00005  * Copyright (C) 2006  Red Hat, Inc. All rights reserved.
00006  *
00007  * This copyrighted material is made available to anyone wishing to use,
00008  * modify, copy, or redistribute it subject to the terms and conditions of
00009  * the GNU General Public License v.2.  This program is distributed in the
00010  * hope that it will be useful, but WITHOUT ANY WARRANTY expressed or
00011  * implied, including the implied warranties of MERCHANTABILITY or FITNESS
00012  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
00013  * details.  You should have received a copy of the GNU General Public
00014  * License along with this program; if not, write to the Free Software
00015  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00016  * USA. Any Red Hat trademarks that are incorporated in the source code or
00017  * documentation are not subject to the GNU General Public License and may
00018  * only be used or replicated with the express permission of Red Hat, Inc.
00019  *
00020  * Red Hat Author(s): Jason Vas Dias
00021  *                    David Cantrell
00022  */
00023 
00024 #include <sys/types.h>
00025 #include <unistd.h>
00026 
00027 #include <sys/socket.h>
00028 #include <arpa/inet.h>
00029 #include <time.h>
00030 #include <search.h>
00031 extern void tdestroy (void *root, void (*free_node)(void *nodep));
00032 #include <stdio.h>
00033 
00034 #include <isc_dhcp/dhcpd.h>
00035 
00036 #include <dhcp4_lease.h>
00037 
00038 static int option_code_comparator( const void *p1, const void *p2 )
00039 {    
00040     const DHCPv4_option *o1 = p1, *o2 = p2;
00041     uint16_t o1code = (o1->unicode << 8) | (o1->code),
00042              o2code = (o2->unicode << 8) | (o2->code);
00043     return
00044         (  ( o1code == o2code ) 
00045            ? 0
00046            :( ( o1code > o2code )
00047               ? 1
00048               : -1
00049             )
00050         );
00051 }
00052 
00053 static int option_name_comparator( const void *p1, const void *p2 )
00054 {
00055     const DHCPv4_option *o1 = p1, *o2 = p2;
00056     return strcmp(o1->name, o2->name);
00057 }
00058 
00059 DHCPv4_option *dhcpv4_get_option_by_code( DHCPv4_lease *l, uint8_t universe, uint8_t code)
00060 {
00061     DHCPv4_option sop, **opp;
00062     sop.unicode = universe;
00063     sop.code = code;
00064     if( (opp = tfind( &sop, &(l->options), option_code_comparator)) != 0L )
00065         return *opp;
00066     return 0L;
00067 }
00068 
00069 DHCPv4_option *dhcpv4_get_option_by_name( DHCPv4_lease *l, char *n)
00070 {
00071     DHCPv4_option sop, **opp;
00072     sop.name = n;
00073     if( (opp = tfind( &sop, &(l->options_by_name), option_name_comparator)) != 0L )
00074         return *opp;
00075     return 0L;
00076 }
00077 
00078 static 
00079 void dhcp4_client_option_add 
00080 (   struct option_cache *oc,
00081     struct packet *packet, 
00082     struct lease *isc_lease,
00083     struct client_state *client,
00084     struct option_state *in_options,
00085     struct option_state *cfg_options,
00086     struct binding_scope **scope,
00087     struct universe *u, 
00088     void   *lease_ptr
00089 );
00090 
00091 DHCPv4_lease *dhcpv4_lease( struct client_state *client )
00092 {
00093     DHCPv4_lease *lease;
00094     struct client_lease *l = client->new ? client->new : client->active;
00095     int i;
00096 /*    char buf1[32], buf2[32], buf3[64], buf4[64], buf5[64], buf6[32], buf7[64];*/
00097 
00098     if ( ( l == 0L ) || (l->address.len != 4) )
00099         return 0L;
00100     
00101     lease = calloc( 1, sizeof(DHCPv4_lease) );
00102 
00103     lease->address.s_addr = 
00104         htonl
00105         ( (l->address.iabuf[0] << 24)
00106          |(l->address.iabuf[1] << 16)
00107          |(l->address.iabuf[2] << 8)
00108          | l->address.iabuf[3]
00109         );
00110 
00111     lease->requested_address.s_addr = 
00112         htonl
00113         ( (client->requested_address.iabuf[0] << 24)
00114          |(client->requested_address.iabuf[1] << 16)
00115          |(client->requested_address.iabuf[2] << 8)
00116          | client->requested_address.iabuf[3]
00117         );
00118 
00119     lease->is_static = l->is_static;
00120     lease->is_bootp = l->is_bootp;
00121     lease->requested = client->first_sending;
00122     lease->expiry = l->expiry;
00123     lease->renewal = l->renewal;
00124     lease->rebind = l->rebind;
00125 
00126     if ( client->interface )
00127     {
00128         lease->if_index = client->interface->index;    
00129         if ( client->interface->name )
00130             lease->if_name = strdup(client->interface->name);
00131     }else
00132         lease->if_index = -1;
00133 
00134     lease->server_address = client->packet.siaddr;
00135     
00136     if ( l->filename )
00137         lease->filename = strdup(l->filename);
00138     
00139     if ( l->server_name )
00140         lease->server_name = strdup(l->server_name);
00141     /*
00142     fprintf(stderr, "DHCPv4 lease:\n\tinterface: %s %d\n\tciaddr: %s\n\trequested addr: %s\n\t"
00143                     "siaddr: %s\n\tfilename: %s\n\tserver_name: %s\n\tis_bootp: %d\n\tis_static: %d\n\t"
00144                     "time requested: %s\n\texpiry time: %s\trenew time: %s\trebind time:%s\n", 
00145             lease->if_name, lease->if_index,
00146             inet_ntop(AF_INET, &( lease->address ),  &(buf1[0]), sizeof(buf1)),
00147             inet_ntop(AF_INET, &( lease->requested_address ),  &(buf6[0]), sizeof(buf6)),
00148             inet_ntop(AF_INET, &( lease->server_address ),  &(buf2[0]), sizeof(buf2)),
00149             lease->filename, lease->server_name,
00150             lease->is_bootp, lease->is_static,
00151             ctime_r((const time_t*)&(lease->requested),&(buf7[0])),
00152             ctime_r((const time_t*)&(lease->expiry),&(buf3[0])),
00153             ctime_r((const time_t*)&(lease->renewal),&(buf4[0])),
00154             ctime_r((const time_t*)&(lease->rebind),&(buf5[0]))
00155         );
00156     */
00157     for (i = 0; i < l -> options -> universe_count; i++) 
00158     {
00159         /*fprintf(stderr,"UNIVERSE: %d %s\n", universes[i]->index, universes[i]->name);*/
00160         option_space_foreach 
00161         (   (struct packet *)0, (struct lease *)0,
00162             client, (struct option_state *)0,
00163             l -> options, &global_scope,
00164             universes [i],
00165             lease, dhcp4_client_option_add
00166         );
00167     }
00168     return lease;
00169 }
00170 
00171 static
00172 void option_free( void *opp )
00173 {
00174     DHCPv4_option *opt = opp;
00175     free(opt->name);
00176     free(opt->format);
00177     free(opt->universe);
00178     free(opt);
00179 }
00180 
00181 void dhcpv4_lease_free( DHCPv4_lease *lease)
00182 {
00183     if(lease->if_name)
00184     {
00185         free(lease->if_name);
00186         lease->if_name = 0;
00187     }
00188     if(lease->filename)
00189     {
00190         free(lease->filename);
00191         lease->filename = 0;
00192     }
00193     if(lease->server_name)
00194     {
00195         free(lease->server_name);
00196         lease->server_name=0;
00197     }
00198     if( lease->options )
00199     {
00200         tdestroy(lease->options, option_free);
00201         lease->options = 0;
00202     }
00203     free(lease);
00204 }
00205 
00206 static void option_twalker( const void *p, const VISIT which, const int depth )
00207 {
00208     DHCPv4_option *option, *const*opp=p;
00209     DHCPv4_lease  *lease;
00210 
00211     if( (opp == 0L) || ((option = *opp) == 0L)
00212       ||( (which != postorder) && (which != leaf) )
00213       ) return;
00214     
00215     lease = option -> lease;
00216     
00217     lease -> handler (option, lease -> handler_arg );
00218 }
00219 
00220 void dhcpv4_process_options ( DHCPv4_lease *lease, DHCPv4_option_handler handler, void *handler_arg)
00221 {    
00222     if ( lease &&  lease->options )
00223     {
00224         lease->handler = handler;
00225         lease->handler_arg = handler_arg;
00226         twalk(lease->options, option_twalker);
00227     }
00228 } 
00229 
00230 #define DHC_PAD( type, total_length ) ( ( sizeof(type) - (total_length  & (sizeof(type)-1) ) ) & (sizeof(type)-1) )
00231 
00232 void dhcp4_client_option_add 
00233 (   struct option_cache *oc,
00234     struct packet *packet, 
00235     struct lease *isc_lease,
00236     struct client_state *client,
00237     struct option_state *in_options,
00238     struct option_state *cfg_options,
00239     struct binding_scope **scope,
00240     struct universe *u, 
00241     void   *lease_ptr
00242 )
00243 {
00244     DHCPv4_lease *lease = lease_ptr;
00245     DHCPv4_option *option;
00246     struct data_string data;
00247     const  uint8_t *dp, *de;
00248     uint8_t *p, *value, *endv, 
00249             is_array = 0, element_pad = 0, **vl;
00250     int fi=0, i=0, length = 0, n_values = 0, total_length = 0, dbg_length=0;
00251     uint32_t intv;
00252     uint16_t sv, n_members=0, n_elements =0, member_size=0;
00253     const uint8_t *dbg_d_last;
00254     uint8_t *dbg_v_last, **dbg_vl_last;
00255     void *dbg_t;
00256     
00257 /*   fprintf(stderr,"dhcp4_client_option_add: %s\n", oc->option->name);*/
00258 
00259     memset (&data, 0, sizeof data);
00260     if ( evaluate_option_cache 
00261          (   &data, packet, isc_lease, client,
00262              in_options, cfg_options, scope, oc, MDL
00263          ) 
00264        ) 
00265     {
00266         if (data.len) 
00267         {
00268 
00269 /*          fprintf(stderr,"\t%s - data len: %d format: %s\n", oc->option->name, data.len, oc->option->format );*/
00270 
00271             /* first calculate length required */
00272             dp = &(data.data[0]);
00273             de = &(data.data[data.len]);
00274             dbg_length = length;
00275             dbg_d_last = dp;
00276             for (fi=0;
00277                 (oc -> option -> format [fi])
00278                &&( (dp < de) 
00279                  ||( (dp == de) 
00280                    &&( (oc -> option -> format [fi] == 'A')
00281                      ||(oc -> option -> format [fi] == 'a')
00282                      )
00283                    )
00284                  );
00285                  fi++
00286                 ) 
00287             {
00288 /*              fprintf(stderr,"\t%d: %c\tdp: %p (%d) length: %d (%d)\n", 
00289                         fi,  oc -> option -> format [fi],
00290                         dp, dp - dbg_d_last, length, length - dbg_length  );
00291 */
00292                 dbg_d_last = dp;
00293                 dbg_length = length;
00294                 switch ( oc-> option -> format [fi] )
00295                 {
00296                 case DHC_T_IP_ADDRESS:
00297                 case DHC_T_UINT32:
00298                 case DHC_T_INT32:
00299                     length += sizeof(uint32_t) + DHC_PAD( uint32_t, length );
00300                     dp += 4;
00301                     n_members++;
00302                     break;
00303 
00304                 case DHC_T_UINT16:
00305                 case DHC_T_INT16:
00306                     length += sizeof(int16_t) + DHC_PAD( int16_t, length );
00307                     dp += 2;
00308                     n_members++;
00309                     break;
00310 
00311                 case DHC_T_ENUMERATION: 
00312                     for(i=0; oc->option->format[fi] && (oc->option->format[fi] != '.'); fi++, i++ );
00313                     /* the width of the enumeration data is meant to be specifiable, but currently is not -
00314                      * All enumeration values are currently bytes (uint8_t) - fall through
00315                      */
00316                 case DHC_T_CHAR:
00317                 case DHC_T_UCHAR:
00318                 case DHC_T_BOOL:
00319                 case DHC_T_IMPLICIT_BOOL:
00320                     length += sizeof(uint8_t) + DHC_PAD(uint8_t, length );
00321                     dp += 1;
00322                     n_members++;
00323                     break;
00324 
00325                 case DHC_T_ENCAPSULATION:
00326                 case DHC_T_ENCAPSULATION_NO_DIRECTIVE:
00327                     /* skip encapsulation name */
00328                     for(i=0; oc -> option -> format[fi] && (oc -> option -> format[fi] != '.'); fi++, i++);
00329                     /* treat encapsulations just like hex strings for now - 
00330                      * fall through 
00331                      */
00332 
00333                 case DHC_T_HEX_STRING:
00334                     length += ( (unsigned long)de - (unsigned long)dp  );
00335                     dp = de ;
00336                     n_members++;
00337                     /* Hex strings will be exactly the remainder of the length,
00338                        and MAY not have a trailing nul byte.
00339                     */
00340                     break;
00341 
00342                 case DHC_T_DOMAIN_NAME:
00343                 case DHC_T_TEXT:
00344                 case DHC_T_OPTION_SPACE:
00345                     length += ( data.len - length );
00346                     if( data.data[data.len - 1] != '\0' )
00347                     {
00348                         length += 1;
00349                         /* text strings will always have at least one nul byte appended */
00350                     }
00351                     dp = de ;
00352                     n_members++;
00353                     break;
00354                     /* note: 
00355                        1. Arrays of strings are not allowed.
00356                        2. There can be only one string per struct
00357                        3. A string member must be the LAST member in a struct
00358                        So the above works OK.
00359                     */
00360 
00361                 case DHC_T_ARRAY:
00362                 case DHC_T_LIST:
00363                     is_array = 1;
00364                     member_size = length;
00365 /*
00366                     fprintf(stderr, "\t\tn_elements: %lu member size: %d\n",
00367                             (((unsigned long)data.len) / ((unsigned long)(dp - &(data.data[0])))),
00368                             member_size
00369                            );                          
00370 */
00371                     n_elements = ( (unsigned long)data.len / (unsigned long )(dp - &(data.data[0])));
00372                     if( n_elements && n_members )
00373                     {
00374                         switch( oc -> option -> format [ 0 ] )
00375                         {
00376                         case DHC_T_IP_ADDRESS:
00377                         case DHC_T_UINT32:
00378                         case DHC_T_INT32:
00379                             length += (element_pad = DHC_PAD(uint32_t, length));
00380                             break;
00381 
00382                         case DHC_T_UINT16:
00383                         case DHC_T_INT16:
00384                             length += (element_pad = DHC_PAD(uint8_t, length));
00385                             break;
00386 
00387                         case DHC_T_CHAR:
00388                         case DHC_T_UCHAR:
00389                         case DHC_T_BOOL:
00390                         case DHC_T_IMPLICIT_BOOL:
00391                         case DHC_T_ENUMERATION: 
00392  
00393                             length += (element_pad = DHC_PAD(uint8_t, length));
00394                         default:
00395                             break;
00396                         }
00397                     }
00398                     length = n_elements * length;
00399                     length -= element_pad; /* no element after last! */
00400                     dp = de;
00401                     if( oc->option->format[fi+1] != '\0' )
00402                     {
00403                         /* not allowed and would make us fail */
00404 /*                      fprintf(stderr, "Array list not the last in format - help!\n");*/
00405                         goto dhcp4_client_option_add_fail ;
00406                     }
00407                     break;
00408 
00409                 case DHC_T_OPTIONAL:
00410                 case DHC_T_NONE:
00411                 default:
00412                     break;                  
00413                 }
00414             }
00415 
00416 /*          fprintf(stderr,"\t%s - length: %d\n", oc->option->name, length);*/
00417 
00418             if( length == 0 )
00419                 return;
00420 
00421             n_values = n_members * (n_elements ? n_elements : 1);
00422 
00423             total_length =
00424                 sizeof( DHCPv4_option ) 
00425               + length  
00426               + (  ( n_values > 1 )
00427                  ? ( ( n_values * sizeof(uint8_t*) )
00428                     +( DHC_PAD ( void*, length ) )
00429                    )
00430                  : 0
00431                 );
00432 
00433 /*          fprintf(stderr,"\t%s - total_length: %d is_array: %d n_members: %d n_elements: %d member_size: %d n_values: %d\n", 
00434                     oc->option->name, total_length, is_array,    n_members,    n_elements,    member_size,    n_values);
00435 */
00436                     
00437             option = malloc( total_length );            
00438 
00439             if( option == 0L )
00440                 return ;            
00441             memset(option, '\0', total_length);
00442             option->lease = lease;
00443             option->name = strdup(oc->option->name);
00444             option->format = strdup(oc->option->format);
00445             option->code = oc->option->code;
00446             option->unicode = u->index;
00447             option->universe = strdup(u->name);
00448             option->length = length;
00449             option->form = 
00450                 is_array
00451                 ? DHCO_ARRAY
00452                 :( ( n_members > 1 )
00453                    ? DHCO_STRUCT
00454                    : DHCO_SCALAR 
00455                  );
00456             if ( option->form == DHCO_STRUCT )
00457             {
00458                 option->size = length ;
00459                 option->n_members = n_members;
00460                 option->n_elements = 0;
00461             }else 
00462             if ( option->form == DHCO_ARRAY )
00463             {
00464                 option->size = member_size;
00465                 option->n_elements = n_elements;
00466                 option->n_members = n_members;
00467             }
00468 
00469 /*          fprintf(stderr, "\tVL size: %d address: %p offset: %d\n",
00470                     ( n_values * sizeof(uint8_t*) ),
00471                     ( n_values > 1 ) ?
00472                     ( (unsigned long)&(option->value[length]) 
00473                     + (unsigned long)(DHC_PAD(void*,length))
00474                     ) : 0, DHC_PAD(void*,length)
00475                 );
00476 */
00477             vl = (void*)
00478                  ( (option->form != DHCO_SCALAR) 
00479                    ?( (unsigned long)&(option->value[length]) 
00480                     + (unsigned long)(DHC_PAD(void*,length))
00481                     )
00482                    : 0L
00483                  );
00484                 
00485 /*          fprintf(stderr,"\toption:\n\tname: %s\n\tformat:%s\n\tuniverse: %d\n\tcode: %d\n\tform: %d\n\tn_members:%d\n\tn_elements: %d\n\tlength: %d\n\t&value[0]: %p\n\tvl: %p\n\tde: %p\n",
00486                     option->name, option->format, option->universe, option->code, option->form, 
00487                     option->n_members, option->n_elements, option->length, &(option->value[0]), vl, 
00488                     &(data.data[data.len]) );
00489 */
00490             
00491             value = &(option->value[0]);
00492             endv = &(option -> value[ length ]);            
00493             dp = &(data.data[0]);
00494             de = &(data.data[data.len]);            
00495             length = 0;
00496             dbg_length = length;
00497             dbg_d_last = dp;
00498             dbg_v_last = value;
00499             dbg_vl_last = vl;
00500 
00501             for ( fi=0;  
00502                   (option -> format [fi]) 
00503                && (dp < de)
00504                && (value < endv);
00505                   fi++
00506                 ) 
00507             {
00508                 if ( vl )
00509                     *vl = value;
00510 
00511 /*              fprintf(stderr, "\t%d %c\tdp:%p (%d) value: %p (%d) vl: %p (%lu) length: %d(%d)\n",
00512                         fi, oc -> option -> format [fi], dp, dp - dbg_d_last,
00513                         value, value - dbg_v_last,
00514                         vl, (unsigned long)vl - (unsigned long)dbg_vl_last,
00515                         length, (length - dbg_length)
00516                     );
00517 */
00518                 dbg_d_last = dp;
00519                 dbg_v_last = value;
00520                 dbg_vl_last = vl;
00521                 dbg_length = length;
00522 
00523                 switch ( oc -> option -> format [fi] )
00524                 {
00525                 case DHC_T_IP_ADDRESS:
00526                     value += DHC_PAD(uint32_t, length);
00527                     length += DHC_PAD(uint32_t, length);
00528                     memcpy(value, dp, sizeof(uint32_t));
00529                     value  += sizeof(uint32_t);
00530                     length += sizeof(uint32_t);
00531                     dp += 4;
00532                     break;
00533 
00534                 case DHC_T_INT32:
00535                 case DHC_T_UINT32:
00536                     value += DHC_PAD(uint32_t, length);
00537                     length += DHC_PAD(uint32_t, length);
00538                     memcpy( &intv, dp, sizeof(uint32_t));
00539                     *((uint32_t*)value) = ntohl( intv );
00540                     value += sizeof(uint32_t);
00541                     length += sizeof(uint32_t);
00542                     dp += 4;
00543                     break;
00544 
00545                 case DHC_T_UINT16:
00546                 case DHC_T_INT16:
00547                     value += DHC_PAD(uint16_t, length);
00548                     length += DHC_PAD(uint16_t, length);
00549                     memcpy( &sv, dp, sizeof(uint16_t));
00550                     *((uint16_t*)value)=ntohs( sv );
00551                     value += sizeof(uint16_t);
00552                     length += sizeof(uint16_t);
00553                     dp += 2;
00554                     break;
00555 
00556                 case DHC_T_ENUMERATION: 
00557                     for(i=0; oc->option->format[fi] && (oc->option->format[fi] != '.'); fi++, i++ );
00558                     /* the width of the enumeration data is meant to be specifiable, but currently is not -
00559                      * All enumeration values are currently bytes (uint8_t) - fall through
00560                      */
00561                 case DHC_T_CHAR:                    
00562                 case DHC_T_UCHAR:
00563                 case DHC_T_BOOL:
00564                 case DHC_T_IMPLICIT_BOOL:
00565                     value += DHC_PAD(uint8_t, length );
00566                     length += DHC_PAD(uint8_t, length );
00567                     *value = *dp;
00568                     value  += sizeof(uint8_t);
00569                     length += sizeof(uint8_t);
00570                     dp += 1;
00571                     break;
00572 
00573                 case DHC_T_ENCAPSULATION:
00574                 case DHC_T_ENCAPSULATION_NO_DIRECTIVE:
00575                     /* skip encapsulation name */
00576                     for(i=0; oc -> option -> format[fi] && (oc -> option -> format[fi] != '.'); fi++, i++);
00577                     /* treat encapsulations just like hex strings for now - 
00578                      * fall through 
00579                      */
00580                 case DHC_T_HEX_STRING:
00581                     memcpy( value, dp, ((unsigned long)de) - ((unsigned long)dp) );
00582                     value += ((unsigned long)de) - ((unsigned long)dp);
00583                     length += ((unsigned long)de) - ((unsigned long)dp);
00584                     dp = de;
00585                     break;
00586 
00587                 case DHC_T_DOMAIN_NAME:
00588                 case DHC_T_TEXT:
00589                 case DHC_T_OPTION_SPACE:
00590                     p = value;
00591                     memcpy( value, dp, ((unsigned long)de) - ((unsigned long)dp) );                 
00592                     value += ((unsigned long)de) - ((unsigned long)dp);
00593                     if( *(de-1) != '\0' )
00594                     {
00595                         *(value++) = '\0';
00596                         length += 1;
00597                     }
00598                     length += (((unsigned long)value) - ((unsigned long)p));
00599                     dp = de;
00600                     break;
00601                                     
00602                 case DHC_T_ARRAY:
00603                 case DHC_T_LIST:
00604                     fi = -1;
00605                     continue;
00606 
00607                 case DHC_T_OPTIONAL:
00608                 case DHC_T_NONE:
00609                     /*XXX to be done!*/
00610                     break;
00611                 }
00612                 if ( vl )
00613                     vl++;
00614             }
00615 
00616 /*          fprintf(stderr," final length: %d option length: %d\n", length, option->length );*/
00617 
00618             if ( (dp != de) || (value != endv) )
00619             {
00620 /*              fprintf(stderr,"fail: dp: %p de: %p value: %p endv: %p\n",
00621                         dp, de, value, endv
00622                     );
00623 */
00624                 goto dhcp4_client_option_add_fail;
00625             }
00626             
00627             dbg_t = tsearch( option,  &(lease->options), option_code_comparator );
00628             dbg_t = tsearch( option,  &(lease->options_by_name), option_name_comparator );
00629             
00630 /*          fprintf(stderr, "\ttsearch: %p\n", dbg_t);*/
00631             return;
00632 
00633         dhcp4_client_option_add_fail:
00634 /*          fprintf(stderr,"dhcp4_client_option_add FAILED!\n");*/
00635             return;
00636         }
00637     }
00638 }
00639 
00640 struct dhcpv4_pack_s
00641 {
00642     DHCPv4_lease *lease;
00643     uint8_t *buf;
00644     uint8_t *bufp;
00645     uint32_t buflen;
00646 };
00647 
00648 void dhcpv4_pack_lease_option(DHCPv4_option *opt, void *psp )
00649 {
00650     struct dhcpv4_pack_s *ps = psp;
00651     uint32_t n_values =
00652         ( (opt->n_elements ? opt->n_elements : 1)
00653          * opt->n_members
00654         ),
00655         name_len = strlen(opt->name),
00656         uni_len = strlen(opt->universe),
00657         fmt_len = strlen(opt->format);
00658 /*        uint8_t *dbg_bufp = ps->bufp;*/
00659 
00660     if( ps->buf )
00661         *((uint32_t*)(ps->bufp))=name_len;
00662     ps->bufp +=sizeof(uint32_t);
00663     if( ps->buf )
00664         memcpy(ps->bufp,opt->name,name_len);
00665     ps->bufp+=name_len + DHC_PAD(uint32_t,name_len);
00666        
00667     if( ps->buf )
00668         *((uint32_t*)(ps->bufp))=uni_len;
00669     ps->bufp+=sizeof(uint32_t);
00670     if( ps->buf )
00671         memcpy(ps->bufp,opt->universe,uni_len);
00672     ps->bufp+=uni_len +  DHC_PAD(uint32_t,uni_len);
00673 
00674     if( ps->buf )
00675         *((uint32_t*)(ps->bufp))=fmt_len;
00676     ps->bufp+=sizeof(uint32_t);
00677     if( ps->buf )
00678         memcpy(ps->bufp,opt->format,fmt_len);
00679     ps->bufp+=fmt_len +  DHC_PAD(uint32_t,fmt_len);
00680 
00681     uint8_t sizeof_opt = ((unsigned long)&(opt->value[0]))-((unsigned long)opt);
00682     if( ps->buf )
00683         memcpy(ps->bufp, opt, sizeof_opt);
00684     ps->bufp += sizeof_opt;
00685     if( ps->buf )
00686         memcpy(ps->bufp, &(opt->value[0]), opt->length);
00687     ps->bufp +=  opt->length
00688               +  DHC_PAD(uint32_t, opt->length)
00689               +  ( ((n_values > 1) ? n_values : 0)  * sizeof(void*));
00690 
00691 /*    fprintf (stderr,"opt: %s %d (%d %d) %d %d\n",opt->name, ps->bufp - dbg_bufp, opt->length, DHC_PAD(uint32_t,opt->length), n_values,  ps->bufp - ps->buf  );*/
00692 }
00693 
00694 int dhcpv4_pack_lease( DHCPv4_lease *lease, uint8_t *buf, uint32_t len )
00695 {
00696     if(lease == 0L)
00697         return 0;
00698 
00699     int filename_len   = lease->filename ? strlen(lease->filename) : 0,
00700         servername_len = lease->server_name ? strlen(lease->server_name) : 0,
00701         ifname_len = lease->if_name ? strlen(lease->if_name) : 0;
00702 
00703     struct dhcpv4_pack_s ps =
00704     {   .lease = lease,
00705         .buf   = buf,
00706         .bufp  = buf,
00707         .buflen= len
00708     };
00709         
00710     if(ps.buf)
00711     {
00712         *((uint32_t*)(ps.bufp)) = len;
00713         ps.bufp += sizeof(uint32_t);
00714     }else
00715         ps.bufp += sizeof(uint32_t);
00716 
00717     if( ps.buf )
00718         memcpy(ps.bufp, lease, sizeof(DHCPv4_lease));
00719 
00720     ps.bufp += sizeof(DHCPv4_lease) + DHC_PAD(uint32_t, sizeof(DHCPv4_lease));   
00721 
00722     if( filename_len )
00723     {
00724         if( ps.buf )
00725             *((uint32_t*)ps.bufp) = filename_len;
00726         ps.bufp+=sizeof(uint32_t);
00727         if( ps.buf )
00728             memcpy(ps.bufp, lease->filename, filename_len);
00729         ps.bufp += filename_len;
00730         ps.bufp += DHC_PAD(uint32_t, filename_len);
00731     }else
00732     {
00733         if( ps.buf )
00734             *((uint32_t*)ps.bufp) = 0;
00735         ps.bufp+=sizeof(uint32_t);
00736     }
00737 
00738     if( servername_len )
00739     {
00740         if( ps.buf )
00741             *((uint32_t*)ps.bufp) = servername_len;
00742         ps.bufp+=sizeof(uint32_t);
00743         if( ps.buf )
00744             memcpy(ps.bufp, lease->server_name, servername_len);
00745         ps.bufp += servername_len;
00746         ps.bufp += DHC_PAD(uint32_t, servername_len);
00747     }else
00748     {
00749         if( ps.buf )
00750             *((uint32_t*)ps.bufp) = 0;
00751         ps.bufp+=sizeof(uint32_t);
00752     }
00753 
00754     if( ifname_len )
00755     {
00756         if( ps.buf )
00757             *((uint32_t*)ps.bufp) = ifname_len;
00758         ps.bufp+=sizeof(uint32_t);
00759         if( ps.buf )
00760             memcpy(ps.bufp, lease->if_name, ifname_len);
00761         ps.bufp += ifname_len;
00762         ps.bufp += DHC_PAD(uint32_t, ifname_len);       
00763     }else
00764     {
00765         if( ps.buf )
00766             *((uint32_t*)ps.bufp) = 0;
00767         ps.bufp+=sizeof(uint32_t);
00768     }   
00769 
00770     dhcpv4_process_options( lease, dhcpv4_pack_lease_option, &ps );
00771         
00772     return (ps.bufp - ps.buf);
00773 }
00774 
00775 DHCPv4_lease *dhcpv4_unpack_lease( uint8_t *buf )
00776 {
00777     if( buf == 0 )
00778         return 0;
00779 
00780     uint32_t packlen = *((uint32_t*)buf);
00781     uint8_t *bufp = buf + sizeof(uint32_t) /*, *dbg_bufp=bufp*/;    
00782     DHCPv4_lease  *rlease = 0;
00783     DHCPv4_option *opt=0, *ropt=0;
00784     uint32_t n_values=0, slen=0;
00785 
00786     if( packlen < (sizeof(DHCPv4_lease) + (2 * sizeof(uint32_t))) )
00787         return 0L;
00788 
00789     rlease = calloc(1, sizeof(DHCPv4_lease));    
00790 
00791     memcpy(rlease, bufp, sizeof(DHCPv4_lease));
00792     rlease->options = 0;
00793     rlease->options_by_name = 0;
00794     rlease->handler = 0;
00795     rlease->handler_arg = 0;
00796     rlease->if_name = 0;
00797     rlease->server_name = 0;
00798     rlease->filename = 0;
00799 
00800     bufp += sizeof(DHCPv4_lease) + DHC_PAD(uint32_t, sizeof(DHCPv4_lease));
00801     
00802     if ((slen = *((uint32_t*)bufp)) > 0)
00803     {   
00804         rlease->filename = calloc(1, slen + 1 );
00805         bufp += sizeof(uint32_t);
00806         memcpy(rlease->filename, bufp, slen); 
00807         bufp += slen + DHC_PAD(uint32_t, slen);
00808     }else
00809         bufp += sizeof(uint32_t);
00810     
00811     if((slen = *((uint32_t*)bufp)) > 0)
00812     {
00813         rlease->server_name = calloc(1, slen + 1 );
00814         bufp += sizeof(uint32_t);
00815         memcpy(rlease->server_name, bufp, slen); 
00816         bufp += slen + DHC_PAD(uint32_t, slen);
00817     }else
00818         bufp += sizeof(uint32_t);    
00819  
00820     if((slen = *((uint32_t*)bufp)) > 0)
00821     {
00822         rlease->if_name = calloc(1, slen + 1 );
00823         bufp += sizeof(uint32_t);
00824         memcpy(rlease->if_name, bufp, slen); 
00825         bufp += slen + DHC_PAD(uint32_t, slen);
00826     }else
00827         bufp += sizeof(uint32_t);        
00828 
00829     while( bufp < (buf + packlen) )
00830     {
00831         char *name, *universe, *format;
00832         void **lv, *lv0,  **rlv;
00833         int nv=0;
00834 
00835         /* dbg_bufp = bufp; */
00836 
00837         slen = *((uint32_t*)bufp);
00838         name = calloc(1, slen + 1);
00839         bufp += sizeof(uint32_t);
00840         memcpy(name, bufp, slen);
00841 
00842         bufp += slen + DHC_PAD(uint32_t, slen);
00843 
00844         slen = *((uint32_t*)bufp);
00845         universe = calloc(1, slen + 1);
00846         bufp += sizeof(uint32_t);
00847         memcpy(universe, bufp, slen);
00848         bufp += slen + DHC_PAD(uint32_t, slen);
00849 
00850         slen = *((uint32_t*)bufp);
00851         format = calloc(1, slen + 1);
00852         bufp += sizeof(uint32_t);
00853         memcpy(format, bufp, slen);
00854         bufp += slen + DHC_PAD(uint32_t, slen);
00855         
00856         opt = (DHCPv4_option*)bufp;
00857 
00858         uint8_t sizeof_opt = ((unsigned long)&(opt->value[0]))-((unsigned long)opt);
00859 
00860         n_values = 
00861             ( (opt->n_elements ? opt->n_elements : 1)
00862              * opt->n_members
00863             );
00864 
00865 /*      fprintf(stderr, "\t%s %d %d %d\n", name, n_values, opt->n_elements, opt->n_members);*/
00866                 
00867         ropt = 
00868             calloc
00869             (1,  sizeof_opt
00870               +  opt->length 
00871               +  DHC_PAD(uint32_t, opt->length)
00872               +  ( ((n_values > 1) ? n_values : 0)  * sizeof(void*))
00873             );
00874         memcpy(ropt, opt, 
00875                  sizeof_opt
00876               +  opt->length 
00877               +  DHC_PAD(uint32_t, opt->length)
00878               +  ( ((n_values > 1) ? n_values : 0)  * sizeof(void*))
00879               );
00880         ropt->name = name;
00881         ropt->universe = universe;
00882         ropt->format = format;
00883         
00884         if( n_values > 1 )
00885         {
00886             lv =  (void*) 
00887                 (  &(opt->value[0])
00888                 +  opt->length 
00889                 +  DHC_PAD(uint32_t, opt->length)
00890                 );
00891 
00892             rlv = (void*)
00893                 (  &(ropt->value[0])
00894                 +  opt->length 
00895                 +  DHC_PAD(uint32_t, opt->length)
00896                 );
00897             
00898             lv0 = *lv;
00899             nv = n_values;
00900             while(nv--)
00901                 *(rlv++)=&(ropt->value[0]) + ((*(lv++))-lv0);
00902         }
00903         bufp +=  sizeof_opt
00904               +  opt->length 
00905               +  DHC_PAD(uint32_t, opt->length)
00906               +  ( ((n_values > 1) ? n_values : 0)  * sizeof(void*))
00907             ;
00908 /*      fprintf(stderr,"unpack: %s %d %d\n", name , bufp - dbg_bufp, n_values); */
00909         ropt->lease = rlease;
00910         tsearch(ropt,&(rlease->options),option_code_comparator);
00911         tsearch(ropt,&(rlease->options_by_name),option_name_comparator);
00912     }
00913     return rlease;
00914 }

Generated on Mon Aug 14 17:26:17 2006 for libdhcp by  doxygen 1.4.7