summaryrefslogtreecommitdiff
path: root/networking/udhcp/clientpacket.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/clientpacket.c')
-rw-r--r--networking/udhcp/clientpacket.c272
1 files changed, 0 insertions, 272 deletions
diff --git a/networking/udhcp/clientpacket.c b/networking/udhcp/clientpacket.c
deleted file mode 100644
index b4a75be02..000000000
--- a/networking/udhcp/clientpacket.c
+++ /dev/null
@@ -1,272 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/* clientpacket.c
3 *
4 * Packet generation and dispatching functions for the DHCP client.
5 *
6 * Russ Dill <Russ.Dill@asu.edu> July 2001
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10#include "common.h"
11#include "dhcpd.h"
12#include "dhcpc.h"
13#include "options.h"
14
15//#include <features.h>
16#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
17#include <netpacket/packet.h>
18#include <net/ethernet.h>
19#else
20#include <asm/types.h>
21#include <linux/if_packet.h>
22#include <linux/if_ether.h>
23#endif
24
25
26/* Create a random xid */
27uint32_t FAST_FUNC random_xid(void)
28{
29 static smallint initialized;
30
31 if (!initialized) {
32 srand(monotonic_us());
33 initialized = 1;
34 }
35 return rand();
36}
37
38
39/* Initialize the packet with the proper defaults */
40static void init_packet(struct dhcp_packet *packet, char type)
41{
42 udhcp_init_header(packet, type);
43 memcpy(packet->chaddr, client_config.client_mac, 6);
44 if (client_config.clientid)
45 add_option_string(packet->options, client_config.clientid);
46 if (client_config.hostname)
47 add_option_string(packet->options, client_config.hostname);
48 if (client_config.fqdn)
49 add_option_string(packet->options, client_config.fqdn);
50 if (type != DHCPDECLINE
51 && type != DHCPRELEASE
52 && client_config.vendorclass
53 ) {
54 add_option_string(packet->options, client_config.vendorclass);
55 }
56}
57
58
59/* Add a parameter request list for stubborn DHCP servers. Pull the data
60 * from the struct in options.c. Don't do bounds checking here because it
61 * goes towards the head of the packet. */
62static void add_param_req_option(struct dhcp_packet *packet)
63{
64 uint8_t c;
65 int end = end_option(packet->options);
66 int i, len = 0;
67
68 for (i = 0; (c = dhcp_options[i].code) != 0; i++) {
69 if (( (dhcp_options[i].flags & OPTION_REQ)
70 && !client_config.no_default_options
71 )
72 || (client_config.opt_mask[c >> 3] & (1 << (c & 7)))
73 ) {
74 packet->options[end + OPT_DATA + len] = c;
75 len++;
76 }
77 }
78 if (len) {
79 packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
80 packet->options[end + OPT_LEN] = len;
81 packet->options[end + OPT_DATA + len] = DHCP_END;
82 }
83}
84
85/* RFC 2131
86 * 4.4.4 Use of broadcast and unicast
87 *
88 * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM
89 * messages, unless the client knows the address of a DHCP server.
90 * The client unicasts DHCPRELEASE messages to the server. Because
91 * the client is declining the use of the IP address supplied by the server,
92 * the client broadcasts DHCPDECLINE messages.
93 *
94 * When the DHCP client knows the address of a DHCP server, in either
95 * INIT or REBOOTING state, the client may use that address
96 * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address.
97 * The client may also use unicast to send DHCPINFORM messages
98 * to a known DHCP server. If the client receives no response to DHCP
99 * messages sent to the IP address of a known DHCP server, the DHCP
100 * client reverts to using the IP broadcast address.
101 */
102
103static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet)
104{
105 return udhcp_send_raw_packet(packet,
106 /*src*/ INADDR_ANY, CLIENT_PORT,
107 /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
108 client_config.ifindex);
109}
110
111
112/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
113int FAST_FUNC send_discover(uint32_t xid, uint32_t requested)
114{
115 struct dhcp_packet packet;
116
117 init_packet(&packet, DHCPDISCOVER);
118 packet.xid = xid;
119 if (requested)
120 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
121 /* Explicitly saying that we want RFC-compliant packets helps
122 * some buggy DHCP servers to NOT send bigger packets */
123 add_simple_option(packet.options, DHCP_MAX_SIZE, htons(576));
124 add_param_req_option(&packet);
125
126 bb_info_msg("Sending discover...");
127 return raw_bcast_from_client_config_ifindex(&packet);
128}
129
130
131/* Broadcast a DHCP request message */
132/* RFC 2131 3.1 paragraph 3:
133 * "The client _broadcasts_ a DHCPREQUEST message..."
134 */
135int FAST_FUNC send_select(uint32_t xid, uint32_t server, uint32_t requested)
136{
137 struct dhcp_packet packet;
138 struct in_addr addr;
139
140 init_packet(&packet, DHCPREQUEST);
141 packet.xid = xid;
142 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
143 add_simple_option(packet.options, DHCP_SERVER_ID, server);
144 add_param_req_option(&packet);
145
146 addr.s_addr = requested;
147 bb_info_msg("Sending select for %s...", inet_ntoa(addr));
148 return raw_bcast_from_client_config_ifindex(&packet);
149}
150
151
152/* Unicast or broadcast a DHCP renew message */
153int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
154{
155 struct dhcp_packet packet;
156
157 init_packet(&packet, DHCPREQUEST);
158 packet.xid = xid;
159 packet.ciaddr = ciaddr;
160 add_param_req_option(&packet);
161
162 bb_info_msg("Sending renew...");
163 if (server)
164 return udhcp_send_kernel_packet(&packet,
165 ciaddr, CLIENT_PORT,
166 server, SERVER_PORT);
167 return raw_bcast_from_client_config_ifindex(&packet);
168}
169
170
171#if ENABLE_FEATURE_UDHCPC_ARPING
172/* Broadcast a DHCP decline message */
173int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested)
174{
175 struct dhcp_packet packet;
176
177 init_packet(&packet, DHCPDECLINE);
178 packet.xid = xid;
179 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
180 add_simple_option(packet.options, DHCP_SERVER_ID, server);
181
182 bb_info_msg("Sending decline...");
183 return raw_bcast_from_client_config_ifindex(&packet);
184}
185#endif
186
187
188/* Unicast a DHCP release message */
189int FAST_FUNC send_release(uint32_t server, uint32_t ciaddr)
190{
191 struct dhcp_packet packet;
192
193 init_packet(&packet, DHCPRELEASE);
194 packet.xid = random_xid();
195 packet.ciaddr = ciaddr;
196
197 add_simple_option(packet.options, DHCP_SERVER_ID, server);
198
199 bb_info_msg("Sending release...");
200 return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
201}
202
203
204/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
205int FAST_FUNC udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
206{
207 int bytes;
208 struct ip_udp_dhcp_packet packet;
209 uint16_t check;
210
211 memset(&packet, 0, sizeof(packet));
212 bytes = safe_read(fd, &packet, sizeof(packet));
213 if (bytes < 0) {
214 log1("Packet read error, ignoring");
215 /* NB: possible down interface, etc. Caller should pause. */
216 return bytes; /* returns -1 */
217 }
218
219 if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) {
220 log1("Packet is too short, ignoring");
221 return -2;
222 }
223
224 if (bytes < ntohs(packet.ip.tot_len)) {
225 /* packet is bigger than sizeof(packet), we did partial read */
226 log1("Oversized packet, ignoring");
227 return -2;
228 }
229
230 /* ignore any extra garbage bytes */
231 bytes = ntohs(packet.ip.tot_len);
232
233 /* make sure its the right packet for us, and that it passes sanity checks */
234 if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
235 || packet.ip.ihl != (sizeof(packet.ip) >> 2)
236 || packet.udp.dest != htons(CLIENT_PORT)
237 /* || bytes > (int) sizeof(packet) - can't happen */
238 || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
239 ) {
240 log1("Unrelated/bogus packet, ignoring");
241 return -2;
242 }
243
244 /* verify IP checksum */
245 check = packet.ip.check;
246 packet.ip.check = 0;
247 if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) {
248 log1("Bad IP header checksum, ignoring");
249 return -2;
250 }
251
252 /* verify UDP checksum. IP header has to be modified for this */
253 memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
254 /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
255 packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
256 check = packet.udp.check;
257 packet.udp.check = 0;
258 if (check && check != udhcp_checksum(&packet, bytes)) {
259 log1("Packet with bad UDP checksum received, ignoring");
260 return -2;
261 }
262
263 memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
264
265 if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) {
266 bb_info_msg("Packet with bad magic, ignoring");
267 return -2;
268 }
269 log1("Got valid DHCP packet");
270 udhcp_dump_packet(dhcp_pkt);
271 return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
272}