iPXE
fakedhcp.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 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 <stdio.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <ipxe/settings.h>
32 #include <ipxe/netdevice.h>
33 #include <ipxe/dhcppkt.h>
34 #include <ipxe/fakedhcp.h>
35 
36 /** @file
37  *
38  * Fake DHCP packets
39  *
40  */
41 
42 /**
43  * Copy settings to DHCP packet
44  *
45  * @v dest Destination DHCP packet
46  * @v source Source settings block
47  * @v encapsulator Encapsulating setting tag number, or zero
48  * @ret rc Return status code
49  */
50 static int copy_encap_settings ( struct dhcp_packet *dest,
51  struct settings *source,
52  unsigned int encapsulator ) {
53  struct setting setting = { .name = "" };
54  unsigned int subtag;
55  unsigned int tag;
56  void *data;
57  int len;
58  int rc;
59 
60  for ( subtag = DHCP_MIN_OPTION; subtag <= DHCP_MAX_OPTION; subtag++ ) {
61  tag = DHCP_ENCAP_OPT ( encapsulator, subtag );
62  switch ( tag ) {
63  case DHCP_EB_ENCAP:
64  case DHCP_VENDOR_ENCAP:
65  /* Process encapsulated settings */
66  if ( ( rc = copy_encap_settings ( dest, source,
67  tag ) ) != 0 )
68  return rc;
69  break;
70  default:
71  /* Copy setting, if present */
72  setting.tag = tag;
73  len = fetch_raw_setting_copy ( source, &setting, &data);
74  if ( len >= 0 ) {
75  rc = dhcppkt_store ( dest, tag, data, len );
76  free ( data );
77  if ( rc != 0 )
78  return rc;
79  }
80  break;
81  }
82  }
83 
84  return 0;
85 }
86 
87 /**
88  * Copy settings to DHCP packet
89  *
90  * @v dest Destination DHCP packet
91  * @v source Source settings block
92  * @ret rc Return status code
93  */
94 static int copy_settings ( struct dhcp_packet *dest,
95  struct settings *source ) {
96  return copy_encap_settings ( dest, source, 0 );
97 }
98 
99 /**
100  * Create fake DHCPDISCOVER packet
101  *
102  * @v netdev Network device
103  * @v data Buffer for DHCP packet
104  * @v max_len Size of DHCP packet buffer
105  * @ret rc Return status code
106  *
107  * Used by external code.
108  */
110  void *data, size_t max_len ) {
111  struct dhcp_packet dhcppkt;
112  struct in_addr ciaddr = { 0 };
113  int rc;
114 
115  if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
116  dhcp_last_xid, ciaddr, data,
117  max_len ) ) != 0 ) {
118  DBG ( "Could not create DHCPDISCOVER: %s\n",
119  strerror ( rc ) );
120  return rc;
121  }
122 
123  return 0;
124 }
125 
126 /**
127  * Create fake DHCPACK packet
128  *
129  * @v netdev Network device
130  * @v data Buffer for DHCP packet
131  * @v max_len Size of DHCP packet buffer
132  * @ret rc Return status code
133  *
134  * Used by external code.
135  */
137  void *data, size_t max_len ) {
138  struct dhcp_packet dhcppkt;
139  int rc;
140 
141  /* Create base DHCPACK packet */
142  if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
143  dhcp_last_xid, NULL, 0,
144  data, max_len ) ) != 0 ) {
145  DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
146  return rc;
147  }
148 
149  /* Merge in globally-scoped settings, then netdev-specific
150  * settings. Do it in this order so that netdev-specific
151  * settings take precedence regardless of stated priorities.
152  */
153  if ( ( rc = copy_settings ( &dhcppkt, NULL ) ) != 0 ) {
154  DBG ( "Could not set DHCPACK global settings: %s\n",
155  strerror ( rc ) );
156  return rc;
157  }
158  if ( ( rc = copy_settings ( &dhcppkt,
159  netdev_settings ( netdev ) ) ) != 0 ) {
160  DBG ( "Could not set DHCPACK netdev settings: %s\n",
161  strerror ( rc ) );
162  return rc;
163  }
164 
165  return 0;
166 }
167 
168 /**
169  * Create fake PXE Boot Server ACK packet
170  *
171  * @v netdev Network device
172  * @v data Buffer for DHCP packet
173  * @v max_len Size of DHCP packet buffer
174  * @ret rc Return status code
175  *
176  * Used by external code.
177  */
179  void *data, size_t max_len ) {
180  struct dhcp_packet dhcppkt;
181  struct settings *proxy_settings;
182  struct settings *pxebs_settings;
183  int rc;
184 
185  /* Identify available settings */
186  proxy_settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
187  pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
188  if ( ( ! proxy_settings ) && ( ! pxebs_settings ) ) {
189  /* No PXE boot server; return the regular DHCPACK */
190  return create_fakedhcpack ( netdev, data, max_len );
191  }
192 
193  /* Create base DHCPACK packet */
194  if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
195  dhcp_last_xid, NULL, 0,
196  data, max_len ) ) != 0 ) {
197  DBG ( "Could not create PXE BS ACK: %s\n",
198  strerror ( rc ) );
199  return rc;
200  }
201 
202  /* Populate ciaddr */
203  fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
204  &dhcppkt.dhcphdr->ciaddr );
205 
206  /* Merge in ProxyDHCP options */
207  if ( proxy_settings &&
208  ( ( rc = copy_settings ( &dhcppkt, proxy_settings ) ) != 0 ) ) {
209  DBG ( "Could not copy ProxyDHCP settings: %s\n",
210  strerror ( rc ) );
211  return rc;
212  }
213 
214  /* Merge in BootServerDHCP options, if present */
215  if ( pxebs_settings &&
216  ( ( rc = copy_settings ( &dhcppkt, pxebs_settings ) ) != 0 ) ) {
217  DBG ( "Could not copy PXE BS settings: %s\n",
218  strerror ( rc ) );
219  return rc;
220  }
221 
222  return 0;
223 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
A DHCP packet.
Definition: dhcppkt.h:20
#define DHCP_EB_ENCAP
Etherboot-specific encapsulated options.
Definition: dhcp.h:332
int fetch_raw_setting_copy(struct settings *settings, const struct setting *setting, void **data)
Fetch value of setting.
Definition: settings.c:825
static void size_t size_t max_len
Definition: entropy.h:153
Error codes.
int fetch_ipv4_setting(struct settings *settings, const struct setting *setting, struct in_addr *inp)
Fetch value of IPv4 address setting.
Definition: settings.c:916
int create_fakedhcpack(struct net_device *netdev, void *data, size_t max_len)
Create fake DHCPACK packet.
Definition: fakedhcp.c:136
int dhcp_create_request(struct dhcp_packet *dhcppkt, struct net_device *netdev, unsigned int msgtype, uint32_t xid, struct in_addr ciaddr, void *data, size_t max_len)
Create DHCP request packet.
Definition: dhcp.c:977
static int copy_settings(struct dhcp_packet *dest, struct settings *source)
Copy settings to DHCP packet.
Definition: fakedhcp.c:94
#define DHCP_MAX_OPTION
Maximum normal DHCP option.
Definition: dhcp.h:517
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:577
int create_fakedhcpdiscover(struct net_device *netdev, void *data, size_t max_len)
Create fake DHCPDISCOVER packet.
Definition: fakedhcp.c:109
#define DHCP_MIN_OPTION
Minimum normal DHCP option.
Definition: dhcp.h:63
const char * name
Name.
Definition: settings.h:28
int dhcp_create_packet(struct dhcp_packet *dhcppkt, struct net_device *netdev, uint8_t msgtype, uint32_t xid, const void *options, size_t options_len, void *data, size_t max_len)
Create a DHCP packet.
Definition: dhcp.c:914
static int copy_encap_settings(struct dhcp_packet *dest, struct settings *source, unsigned int encapsulator)
Copy settings to DHCP packet.
Definition: fakedhcp.c:50
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:43
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define PROXYDHCP_SETTINGS_NAME
Settings block name used for ProxyDHCP responses.
Definition: dhcp.h:689
static struct net_device * netdev
Definition: gdbudp.c:52
struct in_addr ciaddr
"Client" IP address
Definition: dhcp.h:619
#define PXEBS_SETTINGS_NAME
Setting block name used for BootServerDHCP responses.
Definition: dhcp.h:692
static void * dest
Definition: strings.h:176
Configuration settings.
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
#define DHCPDISCOVER
Definition: dhcp.h:195
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
IP address structure.
Definition: in.h:39
A network device.
Definition: netdevice.h:348
int dhcppkt_store(struct dhcp_packet *dhcppkt, unsigned int tag, const void *data, size_t len)
Store value of DHCP packet setting.
Definition: dhcppkt.c:164
A settings block.
Definition: settings.h:132
#define DHCPACK
Definition: dhcp.h:199
A setting.
Definition: settings.h:23
Network device management.
uint32_t dhcp_last_xid
Most recent DHCP transaction ID.
Definition: dhcp.c:123
struct dhcphdr * dhcphdr
The DHCP packet contents.
Definition: dhcppkt.h:24
uint32_t len
Length.
Definition: ena.h:14
struct settings * find_settings(const char *name)
Find settings block.
Definition: settings.c:406
DHCP packets.
#define DHCP_VENDOR_ENCAP
Vendor encapsulated options.
Definition: dhcp.h:90
#define DHCP_ENCAP_OPT(encapsulator, encapsulated)
Construct a tag value for an encapsulated option.
Definition: dhcp.h:41
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
uint64_t tag
Identity tag.
Definition: edd.h:30
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
String functions.
int create_fakepxebsack(struct net_device *netdev, void *data, size_t max_len)
Create fake PXE Boot Server ACK packet.
Definition: fakedhcp.c:178
Fake DHCP packets.