Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/ipconfig/dhcp_proto.c
Parent Directory | Revision Log
Revision 815 -
(hide annotations)
(download)
Fri Apr 24 18:32:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 5007 byte(s)
Fri Apr 24 18:32:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 5007 byte(s)
-updated to klibc-1.5.15
1 | niro | 532 | /* |
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 | niro | 815 | * Returns: |
75 | * 0 = Not handled | ||
76 | * 2 = DHCPOFFER (from dhcp_proto.h) | ||
77 | * 5 = DHCPACK | ||
78 | * 6 = DHCPNACK | ||
79 | niro | 532 | */ |
80 | niro | 815 | static int dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr, |
81 | uint8_t * exts, int extlen) | ||
82 | niro | 532 | { |
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 | niro | 815 | ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPOFFER : 0; |
110 | if (ret == DHCPOFFER && serverid != INADDR_NONE) | ||
111 | niro | 532 | dev->serverid = serverid; |
112 | DEBUG(("\n dhcp offer\n")); | ||
113 | break; | ||
114 | |||
115 | case DHCPACK: | ||
116 | niro | 815 | ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPACK : 0; |
117 | niro | 532 | DEBUG(("\n dhcp ack\n")); |
118 | break; | ||
119 | |||
120 | case DHCPNAK: | ||
121 | niro | 815 | ret = DHCPNAK; |
122 | niro | 532 | DEBUG(("\n dhcp nak\n")); |
123 | break; | ||
124 | } | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * Receive and parse a DHCP packet | ||
130 | niro | 815 | * 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 | niro | 532 | */ |
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 | niro | 815 | if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY || |
155 | /* RFC951 7.5 */ bootp.xid != dev->bootp.xid || | ||
156 | niro | 532 | 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 | niro | 815 | bootp.giaddr = INADDR_ANY; |
176 | niro | 532 | 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 | } |