Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/ipconfig/dhcp_proto.c
Parent Directory | 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)
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 | } |