Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/ipconfig/bootp_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: 4996 byte(s)
-updated to klibc-1.5.19
1 /*
2 * BOOTP packet protocol handling.
3 */
4 #include <sys/types.h>
5 #include <sys/uio.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <time.h>
10 #include <unistd.h>
11 #include <netinet/in.h>
12
13 #include "ipconfig.h"
14 #include "netdev.h"
15 #include "bootp_packet.h"
16 #include "bootp_proto.h"
17 #include "packet.h"
18
19 static uint8_t bootp_options[312] = {
20 [ 0] = 99, 130, 83, 99,/* RFC1048 magic cookie */
21 [ 4] = 1, 4, /* 4- 9 subnet mask */
22 [ 10] = 3, 4, /* 10- 15 default gateway */
23 [ 16] = 5, 8, /* 16- 25 nameserver */
24 [ 26] = 12, 32, /* 26- 59 host name */
25 [ 60] = 40, 32, /* 60- 95 nis domain name */
26 [ 96] = 17, 40, /* 96-137 boot path */
27 [138] = 57, 2, 1, 150, /* 138-141 extension buffer */
28 [142] = 255, /* end of list */
29 };
30
31 /*
32 * Send a plain bootp request packet with options
33 */
34 int bootp_send_request(struct netdev *dev)
35 {
36 struct bootp_hdr bootp;
37 struct iovec iov[] = {
38 /* [0] = ip + udp headers */
39 [1] = {&bootp, sizeof(bootp)},
40 [2] = {bootp_options, 312}
41 };
42
43 memset(&bootp, 0, sizeof(struct bootp_hdr));
44
45 bootp.op = BOOTP_REQUEST, bootp.htype = dev->hwtype;
46 bootp.hlen = dev->hwlen;
47 bootp.xid = dev->bootp.xid;
48 bootp.ciaddr = dev->ip_addr;
49 bootp.secs = htons(time(NULL) - dev->open_time);
50 memcpy(bootp.chaddr, dev->hwaddr, 16);
51
52 dprintf("-> bootp xid 0x%08x secs 0x%08x ",
53 bootp.xid, ntohs(bootp.secs));
54
55 return packet_send(dev, iov, 2);
56 }
57
58 /*
59 * Parse a bootp reply packet
60 */
61 int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr,
62 uint8_t *exts, int extlen)
63 {
64 dev->bootp.gateway = hdr->giaddr;
65 dev->ip_addr = hdr->yiaddr;
66 dev->ip_server = hdr->siaddr;
67 dev->ip_netmask = INADDR_ANY;
68 dev->ip_broadcast = INADDR_ANY;
69 dev->ip_gateway = hdr->giaddr;
70 dev->ip_nameserver[0] = INADDR_ANY;
71 dev->ip_nameserver[1] = INADDR_ANY;
72 dev->hostname[0] = '\0';
73 dev->nisdomainname[0] = '\0';
74 dev->bootpath[0] = '\0';
75 memcpy(&dev->filename, &hdr->boot_file, FNLEN);
76
77 if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
78 exts[2] == 83 && exts[3] == 99) {
79 uint8_t *ext;
80
81 for (ext = exts + 4; ext - exts < extlen;) {
82 int len;
83 uint8_t opt = *ext++;
84
85 if (opt == 0)
86 continue;
87 else if (opt == 255)
88 break;
89
90 len = *ext++;
91
92 switch (opt) {
93 case 1: /* subnet mask */
94 if (len == 4)
95 memcpy(&dev->ip_netmask, ext, 4);
96 break;
97 case 3: /* default gateway */
98 if (len >= 4)
99 memcpy(&dev->ip_gateway, ext, 4);
100 break;
101 case 6: /* DNS server */
102 if (len >= 4)
103 memcpy(&dev->ip_nameserver, ext,
104 len >= 8 ? 8 : 4);
105 break;
106 case 12: /* host name */
107 if (len > sizeof(dev->hostname) - 1)
108 len = sizeof(dev->hostname) - 1;
109 memcpy(&dev->hostname, ext, len);
110 dev->hostname[len] = '\0';
111 break;
112 case 15: /* domain name */
113 if (len > sizeof(dev->dnsdomainname) - 1)
114 len = sizeof(dev->dnsdomainname) - 1;
115 memcpy(&dev->dnsdomainname, ext, len);
116 dev->dnsdomainname[len] = '\0';
117 break;
118 case 17: /* root path */
119 if (len > sizeof(dev->bootpath) - 1)
120 len = sizeof(dev->bootpath) - 1;
121 memcpy(&dev->bootpath, ext, len);
122 dev->bootpath[len] = '\0';
123 break;
124 case 26: /* interface MTU */
125 if (len == 2)
126 dev->mtu = (ext[0] << 8) + ext[1];
127 break;
128 case 28: /* broadcast addr */
129 if (len == 4)
130 memcpy(&dev->ip_broadcast, ext, 4);
131 break;
132 case 40: /* NIS domain name */
133 if (len > sizeof(dev->nisdomainname) - 1)
134 len = sizeof(dev->nisdomainname) - 1;
135 memcpy(&dev->nisdomainname, ext, len);
136 dev->nisdomainname[len] = '\0';
137 break;
138 case 54: /* server identifier */
139 if (len == 4 && !dev->ip_server)
140 memcpy(&dev->ip_server, ext, 4);
141 break;
142 }
143
144 ext += len;
145 }
146 }
147
148 /*
149 * Got packet.
150 */
151 return 1;
152 }
153
154 /*
155 * Receive a bootp reply and parse packet
156 * Returns:
157 *-1 = Error in packet_recv, try again later
158 * 0 = Unexpected packet, discarded
159 * 1 = Correctly received and parsed packet
160 */
161 int bootp_recv_reply(struct netdev *dev)
162 {
163 struct bootp_hdr bootp;
164 uint8_t bootp_options[312];
165 struct iovec iov[] = {
166 /* [0] = ip + udp headers */
167 [1] = {&bootp, sizeof(struct bootp_hdr)},
168 [2] = {bootp_options, 312}
169 };
170 int ret;
171
172 ret = packet_recv(iov, 3);
173 if (ret <= 0)
174 return -1;
175
176 if (ret < sizeof(struct bootp_hdr) ||
177 bootp.op != BOOTP_REPLY || /* RFC951 7.5 */
178 bootp.xid != dev->bootp.xid ||
179 memcmp(bootp.chaddr, dev->hwaddr, 16))
180 return 0;
181
182 ret -= sizeof(struct bootp_hdr);
183
184 return bootp_parse(dev, &bootp, bootp_options, ret);
185 }
186
187 /*
188 * Initialise interface for bootp.
189 */
190 int bootp_init_if(struct netdev *dev)
191 {
192 short flags;
193
194 /*
195 * Get the device flags
196 */
197 if (netdev_getflags(dev, &flags))
198 return -1;
199
200 /*
201 * We can't do DHCP nor BOOTP if this device
202 * doesn't support broadcast.
203 */
204 if (dev->mtu < 364 || (flags & IFF_BROADCAST) == 0) {
205 dev->caps &= ~(CAP_BOOTP | CAP_DHCP);
206 return 0;
207 }
208
209 /*
210 * Get a random XID
211 */
212 dev->bootp.xid = (uint32_t) lrand48();
213 dev->open_time = time(NULL);
214
215 return 0;
216 }