comparison packages/net/tcpip/current/src/lib/bootp_support.c @ 97:ced4577552cd ecos-sw-2000-06-06

Merge from eCos master repository on 2000-06-06-08:44:00-BST
author jlarmour
date Tue, 06 Jun 2000 08:39:36 +0000
parents
children 84e4bde58b26
comparison
equal deleted inserted replaced
96:b15c60e34c84 97:ced4577552cd
1 //==========================================================================
2 //
3 // lib/bootp_support.c
4 //
5 // Minimal BOOTP functions
6 //
7 //==========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Red Hat eCos Public License
12 // Version 1.1 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://www.redhat.com/
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Configurable Operating System,
22 // released September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Red Hat.
25 // Portions created by Red Hat are
26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
27 // All Rights Reserved.
28 // -------------------------------------------
29 //
30 //####COPYRIGHTEND####
31 //####BSDCOPYRIGHTBEGIN####
32 //
33 // -------------------------------------------
34 //
35 // Portions of this software may have been derived from OpenBSD or other sources,
36 // and are covered by the appropriate copyright disclaimers included herein.
37 //
38 // -------------------------------------------
39 //
40 //####BSDCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s): gthomas
45 // Contributors: gthomas
46 // Date: 2000-01-10
47 // Purpose:
48 // Description:
49 //
50 //
51 //####DESCRIPTIONEND####
52 //
53 //==========================================================================
54
55 // BOOTP support
56
57 #include <network.h>
58
59 // This function sets up the interface it the simplest configuration.
60 // Just enough to broadcast a BOOTP request and get a response.
61 // It returns 'true' if a response was obtained.
62 cyg_bool_t
63 do_bootp(const char *intf, struct bootp *recv)
64 {
65 struct sockaddr_in *addrp;
66 struct ifreq ifr;
67 struct sockaddr_in cli_addr, serv_addr, bootp_server_addr;
68 struct ecos_rtentry route;
69 int s, addrlen;
70 int one = 1;
71 struct bootp bootp_xmit;
72 unsigned char mincookie[] = {99,130,83,99,255} ;
73 struct timeval tv;
74
75 // Ensure clean slate
76 route_reinit(); // Force any existing routes to be forgotten
77
78 s = socket(AF_INET, SOCK_DGRAM, 0);
79 if (s < 0) {
80 perror("socket");
81 return false;
82 }
83
84 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
85 perror("setsockopt");
86 return false;
87 }
88
89 addrp = (struct sockaddr_in *) &ifr.ifr_addr;
90 memset(addrp, 0, sizeof(*addrp));
91 addrp->sin_family = AF_INET;
92 addrp->sin_len = sizeof(*addrp);
93 addrp->sin_port = 0;
94 addrp->sin_addr.s_addr = INADDR_ANY;
95
96 strcpy(ifr.ifr_name, intf);
97 if (ioctl(s, SIOCSIFADDR, &ifr)) {
98 perror("SIOCSIFADDR");
99 return false;
100 }
101
102 if (ioctl(s, SIOCSIFNETMASK, &ifr)) {
103 perror("SIOCSIFNETMASK");
104 return false;
105 }
106
107 /* the broadcast address is 255.255.255.255 */
108 memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
109 if (ioctl(s, SIOCSIFBRDADDR, &ifr)) {
110 perror("SIOCSIFBRDADDR");
111 return false;
112 }
113
114 ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
115 if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
116 perror("SIOCSIFFLAGS");
117 return false;
118 }
119
120 if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
121 perror("SIOCGIFHWADDR");
122 return false;
123 }
124
125 // Set up routing
126 /* the broadcast address is 255.255.255.255 */
127 memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
128 memset(&route, 0, sizeof(route));
129 memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
130
131 addrp->sin_family = AF_INET;
132 addrp->sin_port = 0;
133 addrp->sin_addr.s_addr = INADDR_ANY;
134 memcpy(&route.rt_dst, addrp, sizeof(*addrp));
135 memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
136
137 route.rt_dev = ifr.ifr_name;
138 route.rt_flags = RTF_UP|RTF_GATEWAY;
139 route.rt_metric = 0;
140
141 if (ioctl(s, SIOCADDRT, &route)) {
142 if (errno != EEXIST) {
143 perror("SIOCADDRT 3");
144 return false;
145 }
146 }
147
148 memset((char *) &cli_addr, 0, sizeof(cli_addr));
149 cli_addr.sin_family = AF_INET;
150 cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
151 cli_addr.sin_port = htons(IPPORT_BOOTPC);
152
153 if(bind(s, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
154 perror("bind error");
155 return false;
156 }
157 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
158 perror("setsockopt SO_REUSEADDR");
159 return false;
160 }
161 if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
162 perror("setsockopt SO_REUSEPORT");
163 return false;
164 }
165
166 memset((char *) &serv_addr, 0, sizeof(serv_addr));
167 serv_addr.sin_family = AF_INET;
168 serv_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
169 serv_addr.sin_port = htons(IPPORT_BOOTPS);
170
171 // Fill in the BOOTP request
172 bzero(&bootp_xmit, sizeof(bootp_xmit));
173 if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
174 perror("SIOCGIFHWADDR");
175 return false;
176 }
177 bootp_xmit.bp_htype = ifr.ifr_hwaddr.sa_family;
178 bootp_xmit.bp_hlen = IFHWADDRLEN;
179 bcopy(ifr.ifr_hwaddr.sa_data, &bootp_xmit.bp_chaddr, bootp_xmit.bp_hlen);
180
181 bootp_xmit.bp_secs = 0;
182 bcopy(mincookie, bootp_xmit.bp_vend, sizeof(mincookie));
183
184 bootp_xmit.bp_op = BOOTREQUEST;
185
186 if(sendto(s, &bootp_xmit, sizeof(struct bootp), 0,
187 (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
188 perror("sendto error");
189 return false;
190 }
191
192 tv.tv_sec = 5;
193 tv.tv_usec = 0;
194 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
195
196 addrlen = sizeof(bootp_server_addr);
197 if (recvfrom(s, recv, sizeof(struct bootp), 0,
198 (struct sockaddr *)&bootp_server_addr, &addrlen) < 0) {
199 perror("recvfrom error");
200 return false;
201 }
202
203
204 memset(addrp, 0, sizeof(*addrp));
205 addrp->sin_family = AF_INET;
206 addrp->sin_len = sizeof(*addrp);
207 addrp->sin_port = 0;
208 addrp->sin_addr.s_addr = INADDR_ANY;
209
210 strcpy(ifr.ifr_name, intf);
211 if (ioctl(s, SIOCDIFADDR, &ifr)) {
212 perror("SIOCDIFADDR");
213 }
214
215 // Shut down interface so it can be reinitialized
216 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
217 if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
218 perror("SIOCSIFFLAGS");
219 return false;
220 }
221
222 // All done with socket
223 close(s);
224 return true;
225 }
226
227 static char *_bootp_op[] = {"", "REQUEST", "REPLY"};
228 static char *_bootp_hw_type[] = {"", "Ethernet", "Exp Ethernet", "AX25",
229 "Pronet", "Chaos", "IEEE802", "Arcnet"};
230
231 void
232 show_bootp(const char *intf, struct bootp *bp)
233 {
234 int i, len;
235 unsigned char *op, *ap = 0;
236 unsigned char name[128];
237 struct in_addr addr[32];
238 diag_printf("BOOTP[%s] op: %s\n", intf, _bootp_op[bp->bp_op]);
239 diag_printf(" hw_type: %s\n", _bootp_hw_type[bp->bp_htype]);
240 diag_printf(" hw_addr: ");
241 for (i = 0; i < bp->bp_hlen; i++) {
242 diag_printf("%02x", bp->bp_chaddr[i]);
243 if (i != (bp->bp_hlen-1)) diag_printf(":");
244 }
245 diag_printf("\n");
246 diag_printf(" client IP: %s\n", inet_ntoa(bp->bp_ciaddr));
247 diag_printf(" my IP: %s\n", inet_ntoa(bp->bp_yiaddr));
248 diag_printf(" server IP: %s\n", inet_ntoa(bp->bp_siaddr));
249 diag_printf(" gateway IP: %s\n", inet_ntoa(bp->bp_giaddr));
250 if (bp->bp_sname[0]) {
251 diag_printf(" server: %s\n", bp->bp_sname);
252 }
253 if (bp->bp_file[0]) {
254 diag_printf(" file: %s\n", bp->bp_file);
255 }
256 if (bp->bp_vend[0]) {
257 diag_printf(" options:\n");
258 op = &bp->bp_vend[4];
259 while (*op != TAG_END) {
260 switch (*op) {
261 case TAG_SUBNET_MASK:
262 case TAG_GATEWAY:
263 case TAG_IP_BROADCAST:
264 case TAG_DOMAIN_SERVER:
265 ap = (unsigned char *)&addr[0];
266 len = *(op+1);
267 for (i = 0; i < len; i++) {
268 *ap++ = *(op+i+2);
269 }
270 if (*op == TAG_SUBNET_MASK) ap = " subnet mask";
271 if (*op == TAG_GATEWAY) ap = " gateway";
272 if (*op == TAG_IP_BROADCAST) ap = " IP broadcast";
273 if (*op == TAG_DOMAIN_SERVER) ap = "domain server";
274 diag_printf(" %s: ", ap);
275 ap = (unsigned char *)&addr[0];
276 while (len > 0) {
277 diag_printf("%s", inet_ntoa(*(struct in_addr *)ap));
278 len -= sizeof(struct in_addr);
279 ap += sizeof(struct in_addr);
280 if (len) diag_printf(", ");
281 }
282 diag_printf("\n");
283 break;
284 case TAG_DOMAIN_NAME:
285 case TAG_HOST_NAME:
286 for (i = 0; i < *(op+1); i++) {
287 name[i] = *(op+i+2);
288 }
289 name[*(op+1)] = '\0';
290 if (*op == TAG_DOMAIN_NAME) ap = " domain name";
291 if (*op == TAG_HOST_NAME) ap = " host name";
292 diag_printf(" %s: %s\n", ap, name);
293 break;
294 default:
295 diag_printf("Unknown option: %x.%d\n", *op, *(op+1));
296 }
297 op += *(op+1)+2;
298 }
299 }
300 }
301
302 cyg_bool_t
303 get_bootp_option(struct bootp *bp, unsigned char tag, void *opt)
304 {
305 unsigned char *op;
306 unsigned char *val = (unsigned char *)opt;
307 int i;
308 op = &bp->bp_vend[4];
309 while (*op != TAG_END) {
310 if (*op == tag) {
311 for (i = 0; i < *(op+1); i++) {
312 *val++ = *(op+i+2);
313 }
314 return true;
315 }
316 op += *(op+1)+2;
317 }
318 return false;
319 }
320
321 // [Re]initialize the network interface with the info passed from BOOTP
322 cyg_bool_t
323 init_net(const char *intf, struct bootp *bp)
324 {
325 struct sockaddr_in *addrp;
326 struct ifreq ifr;
327 int s;
328 int one = 1;
329 struct ecos_rtentry route;
330 struct in_addr netmask, gateway;
331
332 s = socket(AF_INET, SOCK_DGRAM, 0);
333 if (s < 0) {
334 perror("socket");
335 return false;
336 }
337
338 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
339 perror("setsockopt");
340 return false;
341 }
342
343 addrp = (struct sockaddr_in *) &ifr.ifr_addr;
344 memset(addrp, 0, sizeof(*addrp));
345 addrp->sin_family = AF_INET;
346 addrp->sin_len = sizeof(*addrp);
347 addrp->sin_port = 0;
348 addrp->sin_addr = bp->bp_yiaddr; // The address BOOTP gave us
349
350 strcpy(ifr.ifr_name, intf);
351 if (ioctl(s, SIOCSIFADDR, &ifr)) {
352 perror("SIOCIFADDR");
353 return false;
354 }
355
356 if (get_bootp_option(bp, TAG_SUBNET_MASK, &addrp->sin_addr)) {
357 netmask = addrp->sin_addr;
358 if (ioctl(s, SIOCSIFNETMASK, &ifr)) {
359 perror("SIOCSIFNETMASK");
360 return false;
361 }
362 }
363
364 if (get_bootp_option(bp, TAG_IP_BROADCAST, &addrp->sin_addr)) {
365 if (ioctl(s, SIOCSIFBRDADDR, &ifr)) {
366 perror("SIOCSIFBRDADDR");
367 return false;
368 }
369
370 }
371
372 ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
373 if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
374 perror("SIOCSIFFLAGS");
375 return false;
376 }
377
378 // Set up routing
379 if (get_bootp_option(bp, TAG_GATEWAY, &gateway)) {
380 memset(&route, 0, sizeof(route));
381 addrp->sin_family = AF_INET;
382 addrp->sin_port = 0;
383 addrp->sin_addr.s_addr = *(unsigned int *)&bp->bp_yiaddr & *(unsigned int *)&netmask;
384 memcpy(&route.rt_dst, addrp, sizeof(*addrp));
385 addrp->sin_addr = netmask;
386 memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
387 addrp->sin_addr = gateway;
388 memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
389
390 route.rt_dev = ifr.ifr_name;
391 route.rt_flags = RTF_UP|RTF_GATEWAY;
392 route.rt_metric = 0;
393
394 if (ioctl(s, SIOCADDRT, &route)) {
395 diag_printf("Route - dst: %s", inet_ntoa(((struct sockaddr_in *)&route.rt_dst)->sin_addr));
396 diag_printf(", mask: %s", inet_ntoa(((struct sockaddr_in *)&route.rt_genmask)->sin_addr));
397 diag_printf(", gateway: %s\n", inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
398 if (errno != EEXIST) {
399 perror("SIOCADDRT 3");
400 return false;
401 }
402 }
403 }
404 close(s);
405 return true;
406 }