2
* ipconfig/dhcp_proto.c
4
* DHCP RFC 2131 and 2132
7
#include <linux/types.h> /* for __u8 */
9
#include <netinet/in.h>
16
#include "bootp_packet.h"
17
#include "bootp_proto.h"
18
#include "dhcp_proto.h"
21
static __u8 dhcp_params[] = {
23
3, /* default gateway */
28
26, /* interface mtu */
29
28, /* broadcast addr */
30
40, /* NIS domain name (why?) */
33
static __u8 dhcp_discover_hdr[] = {
34
99, 130, 83, 99, /* bootp cookie */
35
53, 1, DHCPDISCOVER, /* dhcp message type */
36
55, sizeof(dhcp_params),/* parameter list */
39
static __u8 dhcp_request_hdr[] = {
40
99, 130, 83, 99, /* boot cookie */
41
53, 1, DHCPREQUEST, /* dhcp message type */
42
#define SERVER_IP_OFF 9
43
54, 4, 0, 0, 0, 0, /* server IP */
45
50, 4, 0, 0, 0, 0, /* requested IP address */
46
55, sizeof(dhcp_params),/* parameter list */
49
static __u8 dhcp_end[] = {
53
static struct iovec dhcp_discover_iov[] = {
54
/* [0] = ip + udp header */
55
/* [1] = bootp header */
56
[2] = { dhcp_discover_hdr, sizeof(dhcp_discover_hdr) },
57
[3] = { dhcp_params, sizeof(dhcp_params) },
58
[4] = { dhcp_end, sizeof(dhcp_end) }
61
static struct iovec dhcp_request_iov[] = {
62
/* [0] = ip + udp header */
63
/* [1] = bootp header */
64
[2] = { dhcp_request_hdr, sizeof(dhcp_request_hdr) },
65
[3] = { dhcp_params, sizeof(dhcp_params) },
66
[4] = { dhcp_end, sizeof(dhcp_end) }
70
* Parse a DHCP response packet
73
dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr, __u8 *exts, int extlen)
76
__u32 serverid = INADDR_NONE;
79
if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
80
exts[2] == 83 && exts[3] == 99) {
83
for (ext = exts + 4; ext - exts < extlen; ) {
84
__u8 len, *opt = ext++;
95
memcpy(&serverid, opt + 2, 4);
101
ret = bootp_parse(dev, hdr, exts, extlen);
102
if (ret == 1 && serverid != INADDR_NONE)
103
dev->serverid = serverid;
104
DEBUG(("\n dhcp offer\n"));
108
ret = bootp_parse(dev, hdr, exts, extlen);
109
DEBUG(("\n dhcp ack\n"));
114
DEBUG(("\n dhcp nak\n"));
121
* Receive and parse a DHCP packet
123
static int dhcp_recv(struct netdev *dev)
125
struct bootp_hdr bootp;
126
__u8 dhcp_options[1500];
127
struct iovec iov[] = {
128
/* [0] = ip + udp header */
129
[1] = { &bootp, sizeof(struct bootp_hdr) },
130
[2] = { dhcp_options, sizeof(dhcp_options) }
134
ret = packet_recv(iov, 3);
138
DEBUG(("\n dhcp xid %08x ", dev->bootp.xid));
140
if (ret < sizeof(struct bootp_hdr) ||
141
bootp.op != BOOTP_REPLY || /* RFC951 7.5 */
142
bootp.xid != dev->bootp.xid ||
143
memcmp(bootp.chaddr, dev->hwaddr, 16))
146
ret -= sizeof(struct bootp_hdr);
148
return dhcp_parse(dev, &bootp, dhcp_options, ret);
151
static int dhcp_send(struct netdev *dev, struct iovec *vec, int len)
153
struct bootp_hdr bootp;
155
memset(&bootp, 0, sizeof(struct bootp_hdr));
157
bootp.op = BOOTP_REQUEST;
158
bootp.htype = dev->hwtype;
159
bootp.hlen = dev->hwlen;
160
bootp.xid = dev->bootp.xid;
161
bootp.ciaddr = dev->ip_addr;
162
bootp.giaddr = dev->bootp.gateway;
163
bootp.secs = htons(time(NULL) - dev->open_time);
164
memcpy(bootp.chaddr, dev->hwaddr, 16);
166
vec[1].iov_base = &bootp;
167
vec[1].iov_len = sizeof(struct bootp_hdr);
169
DEBUG(("xid %08x secs %d ",
170
bootp.xid, ntohs(bootp.secs)));
172
return packet_send(dev, vec, len);
176
* Send a DHCP discover packet
178
int dhcp_send_discover(struct netdev *dev)
180
dev->ip_addr = INADDR_ANY;
181
dev->ip_gateway = INADDR_ANY;
183
DEBUG(("-> dhcp discover "));
185
return dhcp_send(dev, dhcp_discover_iov, 5);
189
* Receive a DHCP offer packet
191
int dhcp_recv_offer(struct netdev *dev)
193
return dhcp_recv(dev);
197
* Send a DHCP request packet
199
int dhcp_send_request(struct netdev *dev)
201
memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4);
202
memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4);
204
DEBUG(("-> dhcp request "));
206
return dhcp_send(dev, dhcp_request_iov, 5);
210
* Receive a DHCP ack packet
212
int dhcp_recv_ack(struct netdev *dev)
214
return dhcp_recv(dev);