Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/ipconfig/dhcp_proto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 4737 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 /*
2 * DHCP RFC 2131 and 2132
3 */
4 #include <sys/types.h>
5 #include <sys/uio.h>
6 #include <netinet/in.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <time.h>
10
11 #include "ipconfig.h"
12 #include "netdev.h"
13 #include "bootp_packet.h"
14 #include "bootp_proto.h"
15 #include "dhcp_proto.h"
16 #include "packet.h"
17
18 static uint8_t dhcp_params[] = {
19 1, /* subnet mask */
20 3, /* default gateway */
21 6, /* DNS server */
22 12, /* host name */
23 15, /* domain name */
24 17, /* root path */
25 26, /* interface mtu */
26 28, /* broadcast addr */
27 40, /* NIS domain name (why?) */
28 };
29
30 static uint8_t dhcp_discover_hdr[] = {
31 99, 130, 83, 99, /* bootp cookie */
32 53, 1, DHCPDISCOVER, /* dhcp message type */
33 55, sizeof(dhcp_params), /* parameter list */
34 };
35
36 static uint8_t dhcp_request_hdr[] = {
37 99, 130, 83, 99, /* boot cookie */
38 53, 1, DHCPREQUEST, /* dhcp message type */
39 #define SERVER_IP_OFF 9
40 54, 4, 0, 0, 0, 0, /* server IP */
41 #define REQ_IP_OFF 15
42 50, 4, 0, 0, 0, 0, /* requested IP address */
43 55, sizeof(dhcp_params), /* parameter list */
44 };
45
46 static uint8_t dhcp_end[] = {
47 255,
48 };
49
50 /* Both iovecs below have to have the same structure, since dhcp_send()
51 pokes at the internals */
52 #define DHCP_IOV_LEN 6
53
54 static struct iovec dhcp_discover_iov[] = {
55 /* [0] = ip + udp header */
56 /* [1] = bootp header */
57 [2] = {dhcp_discover_hdr, sizeof(dhcp_discover_hdr)},
58 [3] = {dhcp_params, sizeof(dhcp_params)},
59 /* [4] = DHCP vendor class */
60 [5] = {dhcp_end, sizeof(dhcp_end)}
61 };
62
63 static struct iovec dhcp_request_iov[] = {
64 /* [0] = ip + udp header */
65 /* [1] = bootp header */
66 [2] = {dhcp_request_hdr, sizeof(dhcp_request_hdr)},
67 [3] = {dhcp_params, sizeof(dhcp_params)},
68 /* [4] = DHCP vendor class */
69 [5] = {dhcp_end, sizeof(dhcp_end)}
70 };
71
72 /*
73 * Parse a DHCP response packet
74 */
75 static int
76 dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr, uint8_t * exts, int extlen)
77 {
78 uint8_t type = 0;
79 uint32_t serverid = INADDR_NONE;
80 int ret = 0;
81
82 if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
83 exts[2] == 83 && exts[3] == 99) {
84 uint8_t *ext;
85
86 for (ext = exts + 4; ext - exts < extlen;) {
87 uint8_t len, *opt = ext++;
88 if (*opt == 0)
89 continue;
90
91 len = *ext++;
92
93 ext += len;
94
95 if (*opt == 53)
96 type = opt[2];
97 if (*opt == 54)
98 memcpy(&serverid, opt + 2, 4);
99 }
100 }
101
102 switch (type) {
103 case DHCPOFFER:
104 ret = bootp_parse(dev, hdr, exts, extlen);
105 if (ret == 1 && serverid != INADDR_NONE)
106 dev->serverid = serverid;
107 DEBUG(("\n dhcp offer\n"));
108 break;
109
110 case DHCPACK:
111 ret = bootp_parse(dev, hdr, exts, extlen);
112 DEBUG(("\n dhcp ack\n"));
113 break;
114
115 case DHCPNAK:
116 ret = 2;
117 DEBUG(("\n dhcp nak\n"));
118 break;
119 }
120 return ret;
121 }
122
123 /*
124 * Receive and parse a DHCP packet
125 */
126 static int dhcp_recv(struct netdev *dev)
127 {
128 struct bootp_hdr bootp;
129 uint8_t dhcp_options[1500];
130 struct iovec iov[] = {
131 /* [0] = ip + udp header */
132 [1] = {&bootp, sizeof(struct bootp_hdr)},
133 [2] = {dhcp_options, sizeof(dhcp_options)}
134 };
135 int ret;
136
137 ret = packet_recv(iov, 3);
138 if (ret <= 0)
139 return ret;
140
141 DEBUG(("\n dhcp xid %08x ", dev->bootp.xid));
142
143 if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY || /* RFC951 7.5 */
144 bootp.xid != dev->bootp.xid ||
145 memcmp(bootp.chaddr, dev->hwaddr, 16))
146 return 0;
147
148 ret -= sizeof(struct bootp_hdr);
149
150 return dhcp_parse(dev, &bootp, dhcp_options, ret);
151 }
152
153 static int dhcp_send(struct netdev *dev, struct iovec *vec)
154 {
155 struct bootp_hdr bootp;
156
157 memset(&bootp, 0, sizeof(struct bootp_hdr));
158
159 bootp.op = BOOTP_REQUEST;
160 bootp.htype = dev->hwtype;
161 bootp.hlen = dev->hwlen;
162 bootp.xid = dev->bootp.xid;
163 bootp.ciaddr = dev->ip_addr;
164 bootp.giaddr = dev->bootp.gateway;
165 bootp.secs = htons(time(NULL) - dev->open_time);
166 memcpy(bootp.chaddr, dev->hwaddr, 16);
167
168 vec[1].iov_base = &bootp;
169 vec[1].iov_len = sizeof(struct bootp_hdr);
170
171 vec[4].iov_base = vendor_class_identifier;
172 vec[4].iov_len = vendor_class_identifier_len;
173
174 DEBUG(("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs)));
175
176 return packet_send(dev, vec, DHCP_IOV_LEN);
177 }
178
179 /*
180 * Send a DHCP discover packet
181 */
182 int dhcp_send_discover(struct netdev *dev)
183 {
184 dev->ip_addr = INADDR_ANY;
185 dev->ip_gateway = INADDR_ANY;
186
187 DEBUG(("-> dhcp discover "));
188
189 return dhcp_send(dev, dhcp_discover_iov);
190 }
191
192 /*
193 * Receive a DHCP offer packet
194 */
195 int dhcp_recv_offer(struct netdev *dev)
196 {
197 return dhcp_recv(dev);
198 }
199
200 /*
201 * Send a DHCP request packet
202 */
203 int dhcp_send_request(struct netdev *dev)
204 {
205 memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4);
206 memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4);
207
208 DEBUG(("-> dhcp request "));
209
210 return dhcp_send(dev, dhcp_request_iov);
211 }
212
213 /*
214 * Receive a DHCP ack packet
215 */
216 int dhcp_recv_ack(struct netdev *dev)
217 {
218 return dhcp_recv(dev);
219 }