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