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

Generated on Fri Oct 13 18:20:33 2006 for libdhcp by  doxygen 1.4.7