Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (show annotations) (download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 5762 byte(s)
-updated to klibc-1.5.19
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 7
53
54 static struct iovec dhcp_discover_iov[DHCP_IOV_LEN] = {
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] = optional vendor class */
60 /* [5] = optional hostname */
61 /* [6] = {dhcp_end, sizeof(dhcp_end)} */
62 };
63
64 static struct iovec dhcp_request_iov[DHCP_IOV_LEN] = {
65 /* [0] = ip + udp header */
66 /* [1] = bootp header */
67 [2] = {dhcp_request_hdr, sizeof(dhcp_request_hdr)},
68 [3] = {dhcp_params, sizeof(dhcp_params)},
69 /* [4] = optional vendor class */
70 /* [5] = optional hostname */
71 /* [6] = {dhcp_end, sizeof(dhcp_end)} */
72 };
73
74 /*
75 * Parse a DHCP response packet
76 * Returns:
77 * 0 = Unexpected packet, not parsed
78 * 2 = DHCPOFFER (from dhcp_proto.h)
79 * 5 = DHCPACK
80 * 6 = DHCPNACK
81 */
82 static int dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr,
83 uint8_t * exts, int extlen)
84 {
85 uint8_t type = 0;
86 uint32_t serverid = INADDR_NONE;
87 int ret = 0;
88
89 if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
90 exts[2] == 83 && exts[3] == 99) {
91 uint8_t *ext;
92
93 for (ext = exts + 4; ext - exts < extlen;) {
94 uint8_t len, *opt = ext++;
95 if (*opt == 0)
96 continue;
97
98 len = *ext++;
99
100 ext += len;
101
102 if (*opt == 53)
103 type = opt[2];
104 if (*opt == 54)
105 memcpy(&serverid, opt + 2, 4);
106 }
107 }
108
109 switch (type) {
110 case DHCPOFFER:
111 ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPOFFER : 0;
112 if (ret == DHCPOFFER && serverid != INADDR_NONE)
113 dev->serverid = serverid;
114 dprintf("\n dhcp offer\n");
115 break;
116
117 case DHCPACK:
118 ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPACK : 0;
119 dprintf("\n dhcp ack\n");
120 break;
121
122 case DHCPNAK:
123 ret = DHCPNAK;
124 dprintf("\n dhcp nak\n");
125 break;
126 }
127 return ret;
128 }
129
130 /*
131 * Receive and parse a DHCP packet
132 * Returns:
133 *-1 = Error in packet_recv, try again later
134 * 0 = Unexpected packet, discarded
135 * 2 = DHCPOFFER (from dhcp_proto.h)
136 * 5 = DHCPACK
137 * 6 = DHCPNACK
138 */
139 static int dhcp_recv(struct netdev *dev)
140 {
141 struct bootp_hdr bootp;
142 uint8_t dhcp_options[1500];
143 struct iovec iov[] = {
144 /* [0] = ip + udp header */
145 [1] = {&bootp, sizeof(struct bootp_hdr)},
146 [2] = {dhcp_options, sizeof(dhcp_options)}
147 };
148 int ret;
149
150 ret = packet_recv(iov, 3);
151 if (ret == 0)
152 return -1;
153
154 dprintf("\n dhcp xid %08x ", dev->bootp.xid);
155
156 if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY ||
157 /* RFC951 7.5 */ bootp.xid != dev->bootp.xid ||
158 memcmp(bootp.chaddr, dev->hwaddr, 16))
159 return 0;
160
161 ret -= sizeof(struct bootp_hdr);
162
163 return dhcp_parse(dev, &bootp, dhcp_options, ret);
164 }
165
166 static int dhcp_send(struct netdev *dev, struct iovec *vec)
167 {
168 struct bootp_hdr bootp;
169 char dhcp_hostname[SYS_NMLN+2];
170 int i = 4;
171
172 memset(&bootp, 0, sizeof(struct bootp_hdr));
173
174 bootp.op = BOOTP_REQUEST;
175 bootp.htype = dev->hwtype;
176 bootp.hlen = dev->hwlen;
177 bootp.xid = dev->bootp.xid;
178 bootp.ciaddr = INADDR_ANY;
179 bootp.yiaddr = dev->ip_addr;
180 bootp.giaddr = INADDR_ANY;
181 bootp.secs = htons(time(NULL) - dev->open_time);
182 memcpy(bootp.chaddr, dev->hwaddr, 16);
183
184 vec[1].iov_base = &bootp;
185 vec[1].iov_len = sizeof(struct bootp_hdr);
186
187 dprintf("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs));
188
189 if (vendor_class_identifier_len > 2) {
190 vec[i].iov_base = vendor_class_identifier;
191 vec[i].iov_len = vendor_class_identifier_len;
192 i++;
193
194 dprintf("vendor_class_identifier \"%.*s\" ",
195 vendor_class_identifier_len-2,
196 vendor_class_identifier+2);
197 }
198
199 if (dev->reqhostname[0] != '\0') {
200 int len = strlen(dev->reqhostname);
201 dhcp_hostname[0] = 12;
202 dhcp_hostname[1] = len;
203 memcpy(dhcp_hostname+2, dev->reqhostname, len);
204
205 vec[i].iov_base = dhcp_hostname;
206 vec[i].iov_len = len+2;
207 i++;
208
209 printf("hostname %.*s ", len, dhcp_hostname+2);
210 }
211
212 vec[i].iov_base = dhcp_end;
213 vec[i].iov_len = sizeof(dhcp_end);
214
215 return packet_send(dev, vec, i + 1);
216 }
217
218 /*
219 * Send a DHCP discover packet
220 */
221 int dhcp_send_discover(struct netdev *dev)
222 {
223 dev->ip_addr = INADDR_ANY;
224 dev->ip_gateway = INADDR_ANY;
225
226 dprintf("-> dhcp discover ");
227
228 return dhcp_send(dev, dhcp_discover_iov);
229 }
230
231 /*
232 * Receive a DHCP offer packet
233 */
234 int dhcp_recv_offer(struct netdev *dev)
235 {
236 return dhcp_recv(dev);
237 }
238
239 /*
240 * Send a DHCP request packet
241 */
242 int dhcp_send_request(struct netdev *dev)
243 {
244 memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4);
245 memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4);
246
247 dprintf("-> dhcp request ");
248
249 return dhcp_send(dev, dhcp_request_iov);
250 }
251
252 /*
253 * Receive a DHCP ack packet
254 */
255 int dhcp_recv_ack(struct netdev *dev)
256 {
257 return dhcp_recv(dev);
258 }