Annotation of qemu/roms/ipxe/src/net/dhcppkt.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (C) 2008 Michael Brown <[email protected]>.
                      3:  *
                      4:  * This program is free software; you can redistribute it and/or
                      5:  * modify it under the terms of the GNU General Public License as
                      6:  * published by the Free Software Foundation; either version 2 of the
                      7:  * License, or any later version.
                      8:  *
                      9:  * This program is distributed in the hope that it will be useful, but
                     10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     12:  * General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with this program; if not, write to the Free Software
                     16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17:  */
                     18: 
                     19: FILE_LICENCE ( GPL2_OR_LATER );
                     20: 
                     21: #include <stdint.h>
                     22: #include <stdlib.h>
                     23: #include <stdio.h>
                     24: #include <errno.h>
                     25: #include <string.h>
                     26: #include <ipxe/netdevice.h>
                     27: #include <ipxe/dhcp.h>
                     28: #include <ipxe/dhcpopts.h>
                     29: #include <ipxe/dhcppkt.h>
                     30: 
                     31: /** @file
                     32:  *
                     33:  * DHCP packets
                     34:  *
                     35:  */
                     36: 
                     37: /****************************************************************************
                     38:  *
                     39:  * DHCP packet raw interface
                     40:  *
                     41:  */
                     42: 
                     43: /**
                     44:  * Calculate used length of an IPv4 field within a DHCP packet
                     45:  *
                     46:  * @v data             Field data
                     47:  * @v len              Length of field
                     48:  * @ret used           Used length of field
                     49:  */
                     50: static size_t used_len_ipv4 ( const void *data, size_t len __unused ) {
                     51:        const struct in_addr *in = data;
                     52: 
                     53:        return ( in->s_addr ? sizeof ( *in ) : 0 );
                     54: }
                     55: 
                     56: /**
                     57:  * Calculate used length of a string field within a DHCP packet
                     58:  *
                     59:  * @v data             Field data
                     60:  * @v len              Length of field
                     61:  * @ret used           Used length of field
                     62:  */
                     63: static size_t used_len_string ( const void *data, size_t len ) {
                     64:        return strnlen ( data, len );
                     65: }
                     66: 
                     67: /** A dedicated field within a DHCP packet */
                     68: struct dhcp_packet_field {
                     69:        /** Settings tag number */
                     70:        unsigned int tag;
                     71:        /** Offset within DHCP packet */
                     72:        uint16_t offset;
                     73:        /** Length of field */
                     74:        uint16_t len;
                     75:        /** Calculate used length of field
                     76:         *
                     77:         * @v data      Field data
                     78:         * @v len       Length of field
                     79:         * @ret used    Used length of field
                     80:         */
                     81:        size_t ( * used_len ) ( const void *data, size_t len );
                     82: };
                     83: 
                     84: /** Declare a dedicated field within a DHCP packet
                     85:  *
                     86:  * @v _tag             Settings tag number
                     87:  * @v _field           Field name
                     88:  * @v _used_len                Function to calculate used length of field
                     89:  */
                     90: #define DHCP_PACKET_FIELD( _tag, _field, _used_len ) {                 \
                     91:                .tag = (_tag),                                          \
                     92:                .offset = offsetof ( struct dhcphdr, _field ),          \
                     93:                .len = sizeof ( ( ( struct dhcphdr * ) 0 )->_field ),   \
                     94:                .used_len = _used_len,                                  \
                     95:        }
                     96: 
                     97: /** Dedicated fields within a DHCP packet */
                     98: static struct dhcp_packet_field dhcp_packet_fields[] = {
                     99:        DHCP_PACKET_FIELD ( DHCP_EB_YIADDR, yiaddr, used_len_ipv4 ),
                    100:        DHCP_PACKET_FIELD ( DHCP_EB_SIADDR, siaddr, used_len_ipv4 ),
                    101:        DHCP_PACKET_FIELD ( DHCP_TFTP_SERVER_NAME, sname, used_len_string ),
                    102:        DHCP_PACKET_FIELD ( DHCP_BOOTFILE_NAME, file, used_len_string ),
                    103: };
                    104: 
                    105: /**
                    106:  * Get address of a DHCP packet field
                    107:  *
                    108:  * @v dhcphdr          DHCP packet header
                    109:  * @v field            DHCP packet field
                    110:  * @ret data           Packet field data
                    111:  */
                    112: static inline void * dhcp_packet_field ( struct dhcphdr *dhcphdr,
                    113:                                         struct dhcp_packet_field *field ) {
                    114:        return ( ( ( void * ) dhcphdr ) + field->offset );
                    115: }
                    116: 
                    117: /**
                    118:  * Find DHCP packet field corresponding to settings tag number
                    119:  *
                    120:  * @v tag              Settings tag number
                    121:  * @ret field          DHCP packet field, or NULL
                    122:  */
                    123: static struct dhcp_packet_field *
                    124: find_dhcp_packet_field ( unsigned int tag ) {
                    125:        struct dhcp_packet_field *field;
                    126:        unsigned int i;
                    127: 
                    128:        for ( i = 0 ; i < ( sizeof ( dhcp_packet_fields ) /
                    129:                            sizeof ( dhcp_packet_fields[0] ) ) ; i++ ) {
                    130:                field = &dhcp_packet_fields[i];
                    131:                if ( field->tag == tag )
                    132:                        return field;
                    133:        }
                    134:        return NULL;
                    135: }
                    136: 
                    137: /**
                    138:  * Check applicability of DHCP setting
                    139:  *
                    140:  * @v dhcppkt          DHCP packet
                    141:  * @v tag              Setting tag number
                    142:  * @ret applies                Setting applies within this settings block
                    143:  */
                    144: static int dhcppkt_applies ( struct dhcp_packet *dhcppkt __unused,
                    145:                             unsigned int tag ) {
                    146: 
                    147:        return dhcpopt_applies ( tag );
                    148: }
                    149: 
                    150: /**
                    151:  * Store value of DHCP packet setting
                    152:  *
                    153:  * @v dhcppkt          DHCP packet
                    154:  * @v tag              Setting tag number
                    155:  * @v data             Setting data, or NULL to clear setting
                    156:  * @v len              Length of setting data
                    157:  * @ret rc             Return status code
                    158:  */
                    159: int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
                    160:                    const void *data, size_t len ) {
                    161:        struct dhcp_packet_field *field;
                    162:        void *field_data;
                    163: 
                    164:        /* If this is a special field, fill it in */
                    165:        if ( ( field = find_dhcp_packet_field ( tag ) ) != NULL ) {
                    166:                if ( len > field->len )
                    167:                        return -ENOSPC;
                    168:                field_data = dhcp_packet_field ( dhcppkt->dhcphdr, field );
                    169:                memset ( field_data, 0, field->len );
                    170:                memcpy ( dhcp_packet_field ( dhcppkt->dhcphdr, field ),
                    171:                         data, len );
                    172:                /* Erase any equivalent option from the options block */
                    173:                dhcpopt_store ( &dhcppkt->options, tag, NULL, 0 );
                    174:                return 0;
                    175:        }
                    176: 
                    177:        /* Otherwise, use the generic options block */
                    178:        return dhcpopt_store ( &dhcppkt->options, tag, data, len );
                    179: }
                    180: 
                    181: /**
                    182:  * Fetch value of DHCP packet setting
                    183:  *
                    184:  * @v dhcppkt          DHCP packet
                    185:  * @v tag              Setting tag number
                    186:  * @v data             Buffer to fill with setting data
                    187:  * @v len              Length of buffer
                    188:  * @ret len            Length of setting data, or negative error
                    189:  */
                    190: int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
                    191:                    void *data, size_t len ) {
                    192:        struct dhcp_packet_field *field;
                    193:        void *field_data;
                    194:        size_t field_len = 0;
                    195:        
                    196:        /* Identify special field, if any */
                    197:        if ( ( field = find_dhcp_packet_field ( tag ) ) != NULL ) {
                    198:                field_data = dhcp_packet_field ( dhcppkt->dhcphdr, field );
                    199:                field_len = field->used_len ( field_data, field->len );
                    200:        }
                    201: 
                    202:        /* Return special field, if it exists and is populated */
                    203:        if ( field_len ) {
                    204:                if ( len > field_len )
                    205:                        len = field_len;
                    206:                memcpy ( data, field_data, len );
                    207:                return field_len;
                    208:        }
                    209: 
                    210:        /* Otherwise, use the generic options block */
                    211:        return dhcpopt_fetch ( &dhcppkt->options, tag, data, len );
                    212: }
                    213: 
                    214: /****************************************************************************
                    215:  *
                    216:  * DHCP packet settings interface
                    217:  *
                    218:  */
                    219: 
                    220: /**
                    221:  * Check applicability of DHCP setting
                    222:  *
                    223:  * @v settings         Settings block
                    224:  * @v setting          Setting
                    225:  * @ret applies                Setting applies within this settings block
                    226:  */
                    227: static int dhcppkt_settings_applies ( struct settings *settings,
                    228:                                      struct setting *setting ) {
                    229:        struct dhcp_packet *dhcppkt =
                    230:                container_of ( settings, struct dhcp_packet, settings );
                    231: 
                    232:        return dhcppkt_applies ( dhcppkt, setting->tag );
                    233: }
                    234: 
                    235: /**
                    236:  * Store value of DHCP setting
                    237:  *
                    238:  * @v settings         Settings block
                    239:  * @v setting          Setting to store
                    240:  * @v data             Setting data, or NULL to clear setting
                    241:  * @v len              Length of setting data
                    242:  * @ret rc             Return status code
                    243:  */
                    244: static int dhcppkt_settings_store ( struct settings *settings,
                    245:                                    struct setting *setting,
                    246:                                    const void *data, size_t len ) {
                    247:        struct dhcp_packet *dhcppkt =
                    248:                container_of ( settings, struct dhcp_packet, settings );
                    249: 
                    250:        return dhcppkt_store ( dhcppkt, setting->tag, data, len );
                    251: }
                    252: 
                    253: /**
                    254:  * Fetch value of DHCP setting
                    255:  *
                    256:  * @v settings         Settings block, or NULL to search all blocks
                    257:  * @v setting          Setting to fetch
                    258:  * @v data             Buffer to fill with setting data
                    259:  * @v len              Length of buffer
                    260:  * @ret len            Length of setting data, or negative error
                    261:  */
                    262: static int dhcppkt_settings_fetch ( struct settings *settings,
                    263:                                    struct setting *setting,
                    264:                                    void *data, size_t len ) {
                    265:        struct dhcp_packet *dhcppkt =
                    266:                container_of ( settings, struct dhcp_packet, settings );
                    267: 
                    268:        return dhcppkt_fetch ( dhcppkt, setting->tag, data, len );
                    269: }
                    270: 
                    271: /** DHCP settings operations */
                    272: static struct settings_operations dhcppkt_settings_operations = {
                    273:        .applies = dhcppkt_settings_applies,
                    274:        .store = dhcppkt_settings_store,
                    275:        .fetch = dhcppkt_settings_fetch,
                    276: };
                    277: 
                    278: /****************************************************************************
                    279:  *
                    280:  * Constructor
                    281:  *
                    282:  */
                    283: 
                    284: /**
                    285:  * Initialise DHCP packet
                    286:  *
                    287:  * @v dhcppkt          DHCP packet structure to fill in
                    288:  * @v data             DHCP packet raw data
                    289:  * @v max_len          Length of raw data buffer
                    290:  *
                    291:  * Initialise a DHCP packet structure from a data buffer containing a
                    292:  * DHCP packet.
                    293:  */
                    294: void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data,
                    295:                    size_t len ) {
                    296:        ref_init ( &dhcppkt->refcnt, NULL );
                    297:        dhcppkt->dhcphdr = data;
                    298:        dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
                    299:                       ( len - offsetof ( struct dhcphdr, options ) ),
                    300:                       dhcpopt_no_realloc );
                    301:        settings_init ( &dhcppkt->settings,
                    302:                        &dhcppkt_settings_operations, &dhcppkt->refcnt, 0 );
                    303: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.