These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / core / cachedhcp.c
1 /*
2  * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <ipxe/dhcppkt.h>
29 #include <ipxe/init.h>
30 #include <ipxe/netdevice.h>
31 #include <realmode.h>
32 #include <pxe_api.h>
33
34 /** @file
35  *
36  * Cached DHCP packet
37  *
38  */
39
40 /** Cached DHCPACK physical address
41  *
42  * This can be set by the prefix.
43  */
44 uint32_t __bss16 ( cached_dhcpack_phys );
45 #define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
46
47 /** Colour for debug messages */
48 #define colour &cached_dhcpack_phys
49
50 /** Cached DHCPACK */
51 static struct dhcp_packet *cached_dhcpack;
52
53 /**
54  * Cached DHCPACK startup function
55  *
56  */
57 static void cachedhcp_init ( void ) {
58         struct dhcp_packet *dhcppkt;
59         struct dhcp_packet *tmp;
60         struct dhcphdr *dhcphdr;
61         size_t len;
62
63         /* Do nothing if no cached DHCPACK is present */
64         if ( ! cached_dhcpack_phys ) {
65                 DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
66                 return;
67         }
68
69         /* No reliable way to determine length before parsing packet;
70          * start by assuming maximum length permitted by PXE.
71          */
72         len = sizeof ( BOOTPLAYER_t );
73
74         /* Allocate and populate DHCP packet */
75         dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len );
76         if ( ! dhcppkt ) {
77                 DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
78                 return;
79         }
80         dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
81         copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0,
82                          len );
83         dhcppkt_init ( dhcppkt, dhcphdr, len );
84
85         /* Resize packet to required length.  If reallocation fails,
86          * just continue to use the original packet.
87          */
88         len = dhcppkt_len ( dhcppkt );
89         tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) );
90         if ( tmp )
91                 dhcppkt = tmp;
92
93         /* Reinitialise packet at new address */
94         dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
95         dhcppkt_init ( dhcppkt, dhcphdr, len );
96
97         /* Store as cached DHCPACK, and mark original copy as consumed */
98         DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n",
99                cached_dhcpack_phys, len );
100         cached_dhcpack = dhcppkt;
101         cached_dhcpack_phys = 0;
102 }
103
104 /**
105  * Cached DHCPACK startup function
106  *
107  */
108 static void cachedhcp_startup ( void ) {
109
110         /* If cached DHCP packet was not claimed by any network device
111          * during startup, then free it.
112          */
113         if ( cached_dhcpack ) {
114                 DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" );
115                 dhcppkt_put ( cached_dhcpack );
116                 cached_dhcpack = NULL;
117         }
118 }
119
120 /** Cached DHCPACK initialisation function */
121 struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = {
122         .initialise = cachedhcp_init,
123 };
124
125 /** Cached DHCPACK startup function */
126 struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
127         .startup = cachedhcp_startup,
128 };
129
130 /**
131  * Apply cached DHCPACK to network device, if applicable
132  *
133  * @v netdev            Network device
134  * @ret rc              Return status code
135  */
136 static int cachedhcp_probe ( struct net_device *netdev ) {
137         struct ll_protocol *ll_protocol = netdev->ll_protocol;
138         int rc;
139
140         /* Do nothing unless we have a cached DHCPACK */
141         if ( ! cached_dhcpack )
142                 return 0;
143
144         /* Do nothing unless cached DHCPACK's MAC address matches this
145          * network device.
146          */
147         if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr,
148                       ll_protocol->ll_addr_len ) != 0 ) {
149                 DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n",
150                        netdev->name );
151                 return 0;
152         }
153         DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name );
154
155         /* Register as DHCP settings for this network device */
156         if ( ( rc = register_settings ( &cached_dhcpack->settings,
157                                         netdev_settings ( netdev ),
158                                         DHCP_SETTINGS_NAME ) ) != 0 ) {
159                 DBGC ( colour, "CACHEDHCP could not register settings: %s\n",
160                        strerror ( rc ) );
161                 return rc;
162         }
163
164         /* Claim cached DHCPACK */
165         dhcppkt_put ( cached_dhcpack );
166         cached_dhcpack = NULL;
167
168         return 0;
169 }
170
171 /** Cached DHCP packet network device driver */
172 struct net_driver cachedhcp_driver __net_driver = {
173         .name = "cachedhcp",
174         .probe = cachedhcp_probe,
175 };