Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (show annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 5007 byte(s)
-updated to klibc-1.5.15
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 * Returns:
75 * 0 = Not handled
76 * 2 = DHCPOFFER (from dhcp_proto.h)
77 * 5 = DHCPACK
78 * 6 = DHCPNACK
79 */
80 static int dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr,
81 uint8_t * exts, int extlen)
82 {
83 uint8_t type = 0;
84 uint32_t serverid = INADDR_NONE;
85 int ret = 0;
86
87 if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
88 exts[2] == 83 && exts[3] == 99) {
89 uint8_t *ext;
90
91 for (ext = exts + 4; ext - exts < extlen;) {
92 uint8_t len, *opt = ext++;
93 if (*opt == 0)
94 continue;
95
96 len = *ext++;
97
98 ext += len;
99
100 if (*opt == 53)
101 type = opt[2];
102 if (*opt == 54)
103 memcpy(&serverid, opt + 2, 4);
104 }
105 }
106
107 switch (type) {
108 case DHCPOFFER:
109 ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPOFFER : 0;
110 if (ret == DHCPOFFER && serverid != INADDR_NONE)
111 dev->serverid = serverid;
112 DEBUG(("\n dhcp offer\n"));
113 break;
114
115 case DHCPACK:
116 ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPACK : 0;
117 DEBUG(("\n dhcp ack\n"));
118 break;
119
120 case DHCPNAK:
121 ret = DHCPNAK;
122 DEBUG(("\n dhcp nak\n"));
123 break;
124 }
125 return ret;
126 }
127
128 /*
129 * Receive and parse a DHCP packet
130 * Returns:
131 *-1 = Error in packet_recv
132 * 0 = Not handled
133 * 2 = DHCPOFFER (from dhcp_proto.h)
134 * 5 = DHCPACK
135 * 6 = DHCPNACK
136 */
137 static int dhcp_recv(struct netdev *dev)
138 {
139 struct bootp_hdr bootp;
140 uint8_t dhcp_options[1500];
141 struct iovec iov[] = {
142 /* [0] = ip + udp header */
143 [1] = {&bootp, sizeof(struct bootp_hdr)},
144 [2] = {dhcp_options, sizeof(dhcp_options)}
145 };
146 int ret;
147
148 ret = packet_recv(iov, 3);
149 if (ret <= 0)
150 return ret;
151
152 DEBUG(("\n dhcp xid %08x ", dev->bootp.xid));
153
154 if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY ||
155 /* RFC951 7.5 */ bootp.xid != dev->bootp.xid ||
156 memcmp(bootp.chaddr, dev->hwaddr, 16))
157 return 0;
158
159 ret -= sizeof(struct bootp_hdr);
160
161 return dhcp_parse(dev, &bootp, dhcp_options, ret);
162 }
163
164 static int dhcp_send(struct netdev *dev, struct iovec *vec)
165 {
166 struct bootp_hdr bootp;
167
168 memset(&bootp, 0, sizeof(struct bootp_hdr));
169
170 bootp.op = BOOTP_REQUEST;
171 bootp.htype = dev->hwtype;
172 bootp.hlen = dev->hwlen;
173 bootp.xid = dev->bootp.xid;
174 bootp.ciaddr = dev->ip_addr;
175 bootp.giaddr = INADDR_ANY;
176 bootp.secs = htons(time(NULL) - dev->open_time);
177 memcpy(bootp.chaddr, dev->hwaddr, 16);
178
179 vec[1].iov_base = &bootp;
180 vec[1].iov_len = sizeof(struct bootp_hdr);
181
182 vec[4].iov_base = vendor_class_identifier;
183 vec[4].iov_len = vendor_class_identifier_len;
184
185 DEBUG(("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs)));
186
187 return packet_send(dev, vec, DHCP_IOV_LEN);
188 }
189
190 /*
191 * Send a DHCP discover packet
192 */
193 int dhcp_send_discover(struct netdev *dev)
194 {
195 dev->ip_addr = INADDR_ANY;
196 dev->ip_gateway = INADDR_ANY;
197
198 DEBUG(("-> dhcp discover "));
199
200 return dhcp_send(dev, dhcp_discover_iov);
201 }
202
203 /*
204 * Receive a DHCP offer packet
205 */
206 int dhcp_recv_offer(struct netdev *dev)
207 {
208 return dhcp_recv(dev);
209 }
210
211 /*
212 * Send a DHCP request packet
213 */
214 int dhcp_send_request(struct netdev *dev)
215 {
216 memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4);
217 memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4);
218
219 DEBUG(("-> dhcp request "));
220
221 return dhcp_send(dev, dhcp_request_iov);
222 }
223
224 /*
225 * Receive a DHCP ack packet
226 */
227 int dhcp_recv_ack(struct netdev *dev)
228 {
229 return dhcp_recv(dev);
230 }