Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/ipconfig/bootp_proto.c
Parent Directory | Revision Log
Revision 815 -
(show annotations)
(download)
Fri Apr 24 18:32:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 4866 byte(s)
Fri Apr 24 18:32:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 4866 byte(s)
-updated to klibc-1.5.15
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 | DEBUG(("-> 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 | */ |
157 | int bootp_recv_reply(struct netdev *dev) |
158 | { |
159 | struct bootp_hdr bootp; |
160 | uint8_t bootp_options[312]; |
161 | struct iovec iov[] = { |
162 | /* [0] = ip + udp headers */ |
163 | [1] = {&bootp, sizeof(struct bootp_hdr)}, |
164 | [2] = {bootp_options, 312} |
165 | }; |
166 | int ret; |
167 | |
168 | ret = packet_recv(iov, 3); |
169 | if (ret <= 0) |
170 | return ret; |
171 | |
172 | if (ret < sizeof(struct bootp_hdr) || |
173 | bootp.op != BOOTP_REPLY || /* RFC951 7.5 */ |
174 | bootp.xid != dev->bootp.xid || |
175 | memcmp(bootp.chaddr, dev->hwaddr, 16)) |
176 | return 0; |
177 | |
178 | ret -= sizeof(struct bootp_hdr); |
179 | |
180 | return bootp_parse(dev, &bootp, bootp_options, ret); |
181 | } |
182 | |
183 | /* |
184 | * Initialise interface for bootp. |
185 | */ |
186 | int bootp_init_if(struct netdev *dev) |
187 | { |
188 | short flags; |
189 | |
190 | /* |
191 | * Get the device flags |
192 | */ |
193 | if (netdev_getflags(dev, &flags)) |
194 | return -1; |
195 | |
196 | /* |
197 | * We can't do DHCP nor BOOTP if this device |
198 | * doesn't support broadcast. |
199 | */ |
200 | if (dev->mtu < 364 || (flags & IFF_BROADCAST) == 0) { |
201 | dev->caps &= ~(CAP_BOOTP | CAP_DHCP); |
202 | return 0; |
203 | } |
204 | |
205 | /* |
206 | * Get a random XID |
207 | */ |
208 | dev->bootp.xid = (uint32_t) lrand48(); |
209 | dev->open_time = time(NULL); |
210 | |
211 | return 0; |
212 | } |