Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1297 - (hide annotations) (download)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 5768 byte(s)
-updated to klibc-1.5.22 with mntproc definitions patch included
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 niro 1122 #define DHCP_IOV_LEN 7
53 niro 532
54 niro 1122 static struct iovec dhcp_discover_iov[DHCP_IOV_LEN] = {
55 niro 532 /* [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 niro 1122 /* [4] = optional vendor class */
60     /* [5] = optional hostname */
61     /* [6] = {dhcp_end, sizeof(dhcp_end)} */
62 niro 532 };
63    
64 niro 1122 static struct iovec dhcp_request_iov[DHCP_IOV_LEN] = {
65 niro 532 /* [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 niro 1122 /* [4] = optional vendor class */
70     /* [5] = optional hostname */
71     /* [6] = {dhcp_end, sizeof(dhcp_end)} */
72 niro 532 };
73    
74     /*
75     * Parse a DHCP response packet
76 niro 815 * Returns:
77 niro 1122 * 0 = Unexpected packet, not parsed
78 niro 815 * 2 = DHCPOFFER (from dhcp_proto.h)
79     * 5 = DHCPACK
80     * 6 = DHCPNACK
81 niro 532 */
82 niro 815 static int dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr,
83     uint8_t * exts, int extlen)
84 niro 532 {
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 niro 815 ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPOFFER : 0;
112     if (ret == DHCPOFFER && serverid != INADDR_NONE)
113 niro 532 dev->serverid = serverid;
114 niro 1122 dprintf("\n dhcp offer\n");
115 niro 532 break;
116    
117     case DHCPACK:
118 niro 815 ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPACK : 0;
119 niro 1122 dprintf("\n dhcp ack\n");
120 niro 532 break;
121    
122     case DHCPNAK:
123 niro 815 ret = DHCPNAK;
124 niro 1122 dprintf("\n dhcp nak\n");
125 niro 532 break;
126     }
127     return ret;
128     }
129    
130     /*
131     * Receive and parse a DHCP packet
132 niro 815 * Returns:
133 niro 1122 *-1 = Error in packet_recv, try again later
134     * 0 = Unexpected packet, discarded
135 niro 815 * 2 = DHCPOFFER (from dhcp_proto.h)
136     * 5 = DHCPACK
137     * 6 = DHCPNACK
138 niro 532 */
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 niro 1297 ret = packet_recv(dev, iov, 3);
151     if (ret <= 0)
152     return ret;
153 niro 532
154 niro 1122 dprintf("\n dhcp xid %08x ", dev->bootp.xid);
155 niro 532
156 niro 815 if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY ||
157     /* RFC951 7.5 */ bootp.xid != dev->bootp.xid ||
158 niro 532 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 niro 1122 char dhcp_hostname[SYS_NMLN+2];
170     int i = 4;
171 niro 532
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 niro 1122 bootp.ciaddr = INADDR_ANY;
179     bootp.yiaddr = dev->ip_addr;
180 niro 815 bootp.giaddr = INADDR_ANY;
181 niro 532 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 niro 1122 dprintf("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs));
188 niro 532
189 niro 1122 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 niro 532
194 niro 1122 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 niro 532 }
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 niro 1122 dprintf("-> dhcp discover ");
227 niro 532
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 niro 1122 dprintf("-> dhcp request ");
248 niro 532
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     }