dhcp4_lease.c

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

Generated on Thu Aug 10 21:26:25 2006 for libdhcp by  doxygen 1.4.7