Annotation of qemu/roms/ipxe/src/net/dhcppkt.c, revision 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.