Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/ipconfig/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1297 - (show annotations) (download)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 18091 byte(s)
-updated to klibc-1.5.22 with mntproc definitions patch included
1 #include <poll.h>
2 #include <limits.h>
3 #include <setjmp.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <time.h>
8 #include <arpa/inet.h>
9 #include <sys/types.h>
10 #include <sys/time.h>
11 #include <dirent.h>
12 #include <fcntl.h>
13 #include <unistd.h> /* for getopts */
14
15 #include <net/if_arp.h>
16
17 #include "ipconfig.h"
18 #include "netdev.h"
19 #include "bootp_packet.h"
20 #include "bootp_proto.h"
21 #include "dhcp_proto.h"
22 #include "packet.h"
23
24 static const char sysfs_class_net[] = "/sys/class/net";
25 static const char *progname;
26 static jmp_buf abort_buf;
27 static char do_not_config;
28 static unsigned int default_caps = CAP_DHCP | CAP_BOOTP | CAP_RARP;
29 static int loop_timeout = -1;
30 static int configured;
31 static int bringup_first = 0;
32
33 /* DHCP vendor class identifier */
34 char vendor_class_identifier[260];
35 int vendor_class_identifier_len;
36
37 struct state {
38 int state;
39 int restart_state;
40 time_t expire;
41 int retry_period;
42
43 struct netdev *dev;
44 struct state *next;
45 };
46
47 static inline const char *my_inet_ntoa(uint32_t addr)
48 {
49 struct in_addr a;
50
51 a.s_addr = addr;
52
53 return inet_ntoa(a);
54 }
55
56 static void print_device_config(struct netdev *dev)
57 {
58 printf("IP-Config: %s complete (from %s):\n", dev->name,
59 my_inet_ntoa(dev->serverid ? dev->serverid : dev->ip_server));
60 printf(" address: %-16s ", my_inet_ntoa(dev->ip_addr));
61 printf("broadcast: %-16s ", my_inet_ntoa(dev->ip_broadcast));
62 printf("netmask: %-16s\n", my_inet_ntoa(dev->ip_netmask));
63 printf(" gateway: %-16s ", my_inet_ntoa(dev->ip_gateway));
64 printf("dns0 : %-16s ", my_inet_ntoa(dev->ip_nameserver[0]));
65 printf("dns1 : %-16s\n", my_inet_ntoa(dev->ip_nameserver[1]));
66 if (dev->hostname[0])
67 printf(" host : %-64s\n", dev->hostname);
68 if (dev->dnsdomainname[0])
69 printf(" domain : %-64s\n", dev->dnsdomainname);
70 if (dev->nisdomainname[0])
71 printf(" nisdomain: %-64s\n", dev->nisdomainname);
72 printf(" rootserver: %s ", my_inet_ntoa(dev->ip_server));
73 printf("rootpath: %s\n", dev->bootpath);
74 printf(" filename : %s\n", dev->filename);
75 }
76
77 static void configure_device(struct netdev *dev)
78 {
79 if (do_not_config)
80 return;
81
82 if (netdev_setmtu(dev))
83 printf("IP-Config: failed to set MTU on %s to %u\n",
84 dev->name, dev->mtu);
85
86 if (netdev_setaddress(dev))
87 printf("IP-Config: failed to set addresses on %s\n",
88 dev->name);
89 if (netdev_setdefaultroute(dev))
90 printf("IP-Config: failed to set default route on %s\n",
91 dev->name);
92 if (dev->hostname[0] &&
93 sethostname(dev->hostname, strlen(dev->hostname)))
94 printf("IP-Config: failed to set hostname '%s' from %s\n",
95 dev->hostname, dev->name);
96 }
97
98 /*
99 * Escape shell varialbes in git style:
100 * Always start with a single quote ('), then leave all characters
101 * except ' and ! unchanged.
102 */
103 static void write_option(FILE* f, const char* name, const char* chr)
104 {
105
106 fprintf(f, "%s='", name);
107 while (*chr) {
108 switch (*chr) {
109 case '!':
110 case '\'':
111 fprintf(f, "'\\%c'", *chr);
112 break;
113 default:
114 fprintf(f, "%c", *chr);
115 break;
116 }
117 ++chr;
118 }
119 fprintf(f, "'\n");
120 }
121
122 static void dump_device_config(struct netdev *dev)
123 {
124 char fn[40];
125 FILE *f;
126
127 snprintf(fn, sizeof(fn), "/tmp/net-%s.conf", dev->name);
128 f = fopen(fn, "w");
129 if (f) {
130 write_option(f, "DEVICE", dev->name);
131 write_option(f, "IPV4ADDR",
132 my_inet_ntoa(dev->ip_addr));
133 write_option(f, "IPV4BROADCAST",
134 my_inet_ntoa(dev->ip_broadcast));
135 write_option(f, "IPV4NETMASK",
136 my_inet_ntoa(dev->ip_netmask));
137 write_option(f, "IPV4GATEWAY",
138 my_inet_ntoa(dev->ip_gateway));
139 write_option(f, "IPV4DNS0",
140 my_inet_ntoa(dev->ip_nameserver[0]));
141 write_option(f, "IPV4DNS1",
142 my_inet_ntoa(dev->ip_nameserver[1]));
143 write_option(f, "HOSTNAME", dev->hostname);
144 write_option(f, "DNSDOMAIN", dev->dnsdomainname);
145 write_option(f, "NISDOMAIN", dev->nisdomainname);
146 write_option(f, "ROOTSERVER",
147 my_inet_ntoa(dev->ip_server));
148 write_option(f, "ROOTPATH", dev->bootpath);
149 write_option(f, "filename", dev->filename);
150 fclose(f);
151 }
152 }
153
154 static uint32_t inet_class_netmask(uint32_t ip)
155 {
156 ip = ntohl(ip);
157 if (IN_CLASSA(ip))
158 return htonl(IN_CLASSA_NET);
159 if (IN_CLASSB(ip))
160 return htonl(IN_CLASSB_NET);
161 if (IN_CLASSC(ip))
162 return htonl(IN_CLASSC_NET);
163 return INADDR_ANY;
164 }
165
166 static void postprocess_device(struct netdev *dev)
167 {
168 if (dev->ip_netmask == INADDR_ANY) {
169 dev->ip_netmask = inet_class_netmask(dev->ip_addr);
170 printf("IP-Config: %s guessed netmask %s\n",
171 dev->name, my_inet_ntoa(dev->ip_netmask));
172 }
173 if (dev->ip_broadcast == INADDR_ANY) {
174 dev->ip_broadcast =
175 (dev->ip_addr & dev->ip_netmask) | ~dev->ip_netmask;
176 printf("IP-Config: %s guessed broadcast address %s\n",
177 dev->name, my_inet_ntoa(dev->ip_broadcast));
178 }
179 if (dev->ip_nameserver[0] == INADDR_ANY) {
180 dev->ip_nameserver[0] = dev->ip_server;
181 printf("IP-Config: %s guessed nameserver address %s\n",
182 dev->name, my_inet_ntoa(dev->ip_nameserver[0]));
183 }
184 }
185
186 static void complete_device(struct netdev *dev)
187 {
188 postprocess_device(dev);
189 configure_device(dev);
190 dump_device_config(dev);
191 print_device_config(dev);
192
193 ++configured;
194
195 dev->next = ifaces;
196 ifaces = dev;
197 }
198
199 /*
200 * Returns:
201 * 0 = Not handled, try again later
202 * 1 = Handled
203 */
204 static int process_receive_event(struct state *s, time_t now)
205 {
206 int handled = 1;
207
208 switch (s->state) {
209 case DEVST_ERROR:
210 return 0; /* Not handled */
211 case DEVST_COMPLETE:
212 return 0; /* Not handled as already configured */
213
214 case DEVST_BOOTP:
215 s->restart_state = DEVST_BOOTP;
216 switch (bootp_recv_reply(s->dev)) {
217 case -1:
218 s->state = DEVST_ERROR;
219 break;
220 case 0:
221 handled = 0;
222 break;
223 case 1:
224 s->state = DEVST_COMPLETE;
225 dprintf("\n bootp reply\n");
226 break;
227 }
228 break;
229
230 case DEVST_DHCPDISC:
231 s->restart_state = DEVST_DHCPDISC;
232 switch (dhcp_recv_offer(s->dev)) {
233 case -1:
234 s->state = DEVST_ERROR;
235 break;
236 case 0:
237 handled = 0;
238 break;
239 case DHCPOFFER: /* Offer received */
240 s->state = DEVST_DHCPREQ;
241 dhcp_send_request(s->dev);
242 break;
243 }
244 break;
245
246 case DEVST_DHCPREQ:
247 s->restart_state = DEVST_DHCPDISC;
248 switch (dhcp_recv_ack(s->dev)) {
249 case -1: /* error */
250 s->state = DEVST_ERROR;
251 break;
252 case 0:
253 handled = 0;
254 break;
255 case DHCPACK: /* ACK received */
256 s->state = DEVST_COMPLETE;
257 break;
258 case DHCPNAK: /* NAK received */
259 s->state = DEVST_DHCPDISC;
260 break;
261 }
262 break;
263
264 default:
265 dprintf("\n");
266 handled = 0;
267 break;
268 }
269
270 switch (s->state) {
271 case DEVST_COMPLETE:
272 complete_device(s->dev);
273 break;
274
275 case DEVST_ERROR:
276 /* error occurred, try again in 10 seconds */
277 s->expire = now + 10;
278 break;
279 }
280
281 return handled;
282 }
283
284 static void process_timeout_event(struct state *s, time_t now)
285 {
286 int ret = 0;
287
288 /*
289 * Is the link up? If not, try again in 1 second.
290 */
291 if (!netdev_running(s->dev)) {
292 s->expire = now + 1;
293 s->state = s->restart_state;
294 return;
295 }
296
297 /*
298 * If we had an error, restore a sane state to
299 * restart from.
300 */
301 if (s->state == DEVST_ERROR)
302 s->state = s->restart_state;
303
304 /*
305 * Now send a packet depending on our state.
306 */
307 switch (s->state) {
308 case DEVST_BOOTP:
309 ret = bootp_send_request(s->dev);
310 s->restart_state = DEVST_BOOTP;
311 break;
312
313 case DEVST_DHCPDISC:
314 ret = dhcp_send_discover(s->dev);
315 s->restart_state = DEVST_DHCPDISC;
316 break;
317
318 case DEVST_DHCPREQ:
319 ret = dhcp_send_request(s->dev);
320 s->restart_state = DEVST_DHCPDISC;
321 break;
322 }
323
324 if (ret == -1) {
325 s->state = DEVST_ERROR;
326 s->expire = now + 10;
327 } else {
328 s->expire = now + s->retry_period;
329
330 s->retry_period *= 2;
331 if (s->retry_period > 60)
332 s->retry_period = 60;
333 }
334 }
335
336 static struct state *slist;
337 struct netdev *ifaces;
338
339 /*
340 * Returns:
341 * 0 = No dhcp/bootp packet was received
342 * 1 = A packet was received and handled
343 */
344 static int do_pkt_recv(int pkt_fd, time_t now)
345 {
346 int ret;
347 struct state *s;
348
349 for (s = slist; s; s = s->next) {
350 ret |= process_receive_event(s, now);
351 }
352 return ret;
353 }
354
355 static int loop(void)
356 {
357 #define NR_FDS 1
358 struct pollfd fds[NR_FDS];
359 struct state *s;
360 int pkt_fd;
361 int nr = 0, rc = 0;
362 struct timeval now, prev;
363 time_t start;
364
365 pkt_fd = packet_open();
366 if (pkt_fd == -1) {
367 perror("packet_open");
368 return -1;
369 }
370
371 fds[0].fd = pkt_fd;
372 fds[0].events = POLLRDNORM;
373
374 gettimeofday(&now, NULL);
375 start = now.tv_sec;
376 while (1) {
377 int timeout = 60;
378 int pending = 0;
379 int done = 0;
380 int timeout_ms;
381 int x;
382
383 for (s = slist; s; s = s->next) {
384 dprintf("%s: state = %d\n", s->dev->name, s->state);
385
386 if (s->state == DEVST_COMPLETE) {
387 done++;
388 continue;
389 }
390
391 pending++;
392
393 if (s->expire - now.tv_sec <= 0) {
394 dprintf("timeout\n");
395 process_timeout_event(s, now.tv_sec);
396 }
397
398 if (timeout > s->expire - now.tv_sec)
399 timeout = s->expire - now.tv_sec;
400 }
401
402 if (pending == 0 || (bringup_first && done))
403 break;
404
405 timeout_ms = timeout * 1000;
406
407 for (x = 0; x < 2; x++) {
408 int delta_ms;
409
410 if (timeout_ms <= 0)
411 timeout_ms = 100;
412
413 nr = poll(fds, NR_FDS, timeout_ms);
414 prev = now;
415 gettimeofday(&now, NULL);
416
417 if ((fds[0].revents & POLLRDNORM)) {
418 if (do_pkt_recv(pkt_fd, now.tv_sec) == 1)
419 break;
420 }
421
422 if (loop_timeout >= 0 &&
423 now.tv_sec - start >= loop_timeout) {
424 printf("IP-Config: no response after %d "
425 "secs - giving up\n", loop_timeout);
426 rc = -1;
427 goto bail;
428 }
429
430 delta_ms = (now.tv_sec - prev.tv_sec) * 1000;
431 delta_ms += (now.tv_usec - prev.tv_usec) / 1000;
432
433 dprintf("Delta: %d ms\n", delta_ms);
434
435 timeout_ms -= delta_ms;
436 }
437 }
438 bail:
439 packet_close();
440
441 return rc;
442 }
443
444 static int add_one_dev(struct netdev *dev)
445 {
446 struct state *state;
447
448 state = malloc(sizeof(struct state));
449 if (!state)
450 return -1;
451
452 state->dev = dev;
453 state->expire = time(NULL);
454 state->retry_period = 1;
455
456 /*
457 * Select the state that we start from.
458 */
459 if (dev->caps & CAP_DHCP && dev->ip_addr == INADDR_ANY) {
460 state->restart_state = state->state = DEVST_DHCPDISC;
461 } else if (dev->caps & CAP_DHCP) {
462 state->restart_state = state->state = DEVST_DHCPREQ;
463 } else if (dev->caps & CAP_BOOTP) {
464 state->restart_state = state->state = DEVST_BOOTP;
465 }
466
467 state->next = slist;
468 slist = state;
469
470 return 0;
471 }
472
473 static void parse_addr(uint32_t * addr, const char *ip)
474 {
475 struct in_addr in;
476 if (inet_aton(ip, &in) == 0) {
477 fprintf(stderr, "%s: can't parse IP address '%s'\n",
478 progname, ip);
479 longjmp(abort_buf, 1);
480 }
481 *addr = in.s_addr;
482 }
483
484 static unsigned int parse_proto(const char *ip)
485 {
486 unsigned int caps = 0;
487
488 if (*ip == '\0' || strcmp(ip, "on") == 0 || strcmp(ip, "any") == 0)
489 caps = CAP_BOOTP | CAP_DHCP | CAP_RARP;
490 else if (strcmp(ip, "both") == 0)
491 caps = CAP_BOOTP | CAP_RARP;
492 else if (strcmp(ip, "dhcp") == 0)
493 caps = CAP_BOOTP | CAP_DHCP;
494 else if (strcmp(ip, "bootp") == 0)
495 caps = CAP_BOOTP;
496 else if (strcmp(ip, "rarp") == 0)
497 caps = CAP_RARP;
498 else if (strcmp(ip, "none") == 0 || strcmp(ip, "static") == 0
499 || strcmp(ip, "off") == 0)
500 goto bail;
501 else {
502 fprintf(stderr, "%s: invalid protocol '%s'\n", progname, ip);
503 longjmp(abort_buf, 1);
504 }
505 bail:
506 return caps;
507 }
508
509 static int add_all_devices(struct netdev *template);
510
511 static int parse_device(struct netdev *dev, const char *ip)
512 {
513 char *cp;
514 int opt;
515 int is_ip = 0;
516
517 dprintf("IP-Config: parse_device: \"%s\"\n", ip);
518
519 if (strncmp(ip, "ip=", 3) == 0) {
520 ip += 3;
521 is_ip = 1;
522 } else if (strncmp(ip, "nfsaddrs=", 9) == 0) {
523 ip += 9;
524 is_ip = 1; /* Not sure about this...? */
525 }
526
527 if (!strchr(ip, ':')) {
528 /* Only one option, e.g. "ip=dhcp", or an interface name */
529 if (is_ip) {
530 dev->caps = parse_proto(ip);
531 bringup_first = 1;
532 } else {
533 dev->name = ip;
534 }
535 } else {
536 for (opt = 0; ip && *ip; ip = cp, opt++) {
537 if ((cp = strchr(ip, ':'))) {
538 *cp++ = '\0';
539 }
540 if (opt > 6) {
541 fprintf(stderr,
542 "%s: too many options for %s\n",
543 progname, dev->name);
544 longjmp(abort_buf, 1);
545 }
546
547 if (*ip == '\0')
548 continue;
549 dprintf("IP-Config: opt #%d: '%s'\n", opt, ip);
550 switch (opt) {
551 case 0:
552 parse_addr(&dev->ip_addr, ip);
553 dev->caps = 0;
554 break;
555 case 1:
556 parse_addr(&dev->ip_server, ip);
557 break;
558 case 2:
559 parse_addr(&dev->ip_gateway, ip);
560 break;
561 case 3:
562 parse_addr(&dev->ip_netmask, ip);
563 break;
564 case 4:
565 strncpy(dev->hostname, ip, SYS_NMLN - 1);
566 dev->hostname[SYS_NMLN - 1] = '\0';
567 memcpy(dev->reqhostname, dev->hostname,
568 SYS_NMLN);
569 break;
570 case 5:
571 dev->name = ip;
572 break;
573 case 6:
574 dev->caps = parse_proto(ip);
575 break;
576 }
577 }
578 }
579
580 if (dev->name == NULL ||
581 dev->name[0] == '\0' || strcmp(dev->name, "all") == 0) {
582 add_all_devices(dev);
583 bringup_first = 1;
584 return 0;
585 }
586 return 1;
587 }
588
589 static void bringup_device(struct netdev *dev)
590 {
591 if (netdev_up(dev) == 0) {
592 if (dev->caps) {
593 add_one_dev(dev);
594 } else {
595 complete_device(dev);
596 }
597 }
598 }
599
600 static void bringup_one_dev(struct netdev *template, struct netdev *dev)
601 {
602 if (template->ip_addr != INADDR_NONE)
603 dev->ip_addr = template->ip_addr;
604 if (template->ip_server != INADDR_NONE)
605 dev->ip_server = template->ip_server;
606 if (template->ip_gateway != INADDR_NONE)
607 dev->ip_gateway = template->ip_gateway;
608 if (template->ip_netmask != INADDR_NONE)
609 dev->ip_netmask = template->ip_netmask;
610 if (template->ip_nameserver[0] != INADDR_NONE)
611 dev->ip_nameserver[0] = template->ip_nameserver[0];
612 if (template->ip_nameserver[1] != INADDR_NONE)
613 dev->ip_nameserver[1] = template->ip_nameserver[1];
614 if (template->hostname[0] != '\0')
615 strcpy(dev->hostname, template->hostname);
616 if (template->reqhostname[0] != '\0')
617 strcpy(dev->reqhostname, template->reqhostname);
618 dev->caps &= template->caps;
619
620 bringup_device(dev);
621 }
622
623 static struct netdev *add_device(const char *info)
624 {
625 struct netdev *dev;
626 int i;
627
628 dev = malloc(sizeof(struct netdev));
629 if (dev == NULL) {
630 fprintf(stderr, "%s: out of memory\n", progname);
631 longjmp(abort_buf, 1);
632 }
633
634 memset(dev, 0, sizeof(struct netdev));
635 dev->caps = default_caps;
636
637 if (parse_device(dev, info) == 0)
638 goto bail;
639
640 if (netdev_init_if(dev) == -1)
641 goto bail;
642
643 if (bootp_init_if(dev) == -1)
644 goto bail;
645
646 printf("IP-Config: %s hardware address", dev->name);
647 for (i = 0; i < dev->hwlen; i++)
648 printf("%c%02x", i == 0 ? ' ' : ':', dev->hwaddr[i]);
649 printf(" mtu %d%s%s\n", dev->mtu,
650 dev->caps & CAP_DHCP ? " DHCP" :
651 dev->caps & CAP_BOOTP ? " BOOTP" : "",
652 dev->caps & CAP_RARP ? " RARP" : "");
653 return dev;
654 bail:
655 free(dev);
656 return NULL;
657 }
658
659 static int add_all_devices(struct netdev *template)
660 {
661 DIR *d;
662 struct dirent *de;
663 struct netdev *dev;
664 char t[PATH_MAX], p[255];
665 int i, fd;
666 unsigned long flags;
667
668 d = opendir(sysfs_class_net);
669 if (!d)
670 return 0;
671
672 while ((de = readdir(d)) != NULL) {
673 /* This excludes devices beginning with dots or "dummy",
674 as well as . or .. */
675 if (de->d_name[0] == '.' || !strcmp(de->d_name, ".."))
676 continue;
677 i = snprintf(t, PATH_MAX - 1, "%s/%s/flags", sysfs_class_net,
678 de->d_name);
679 if (i < 0 || i >= PATH_MAX - 1)
680 continue;
681 t[i] = '\0';
682 fd = open(t, O_RDONLY);
683 if (fd < 0) {
684 perror(t);
685 continue;
686 }
687 i = read(fd, &p, sizeof(p) - 1);
688 close(fd);
689 if (i < 0) {
690 perror(t);
691 continue;
692 }
693 p[i] = '\0';
694 flags = strtoul(p, NULL, 0);
695 /* Heuristic for if this is a reasonable boot interface.
696 This is the same
697 logic the in-kernel ipconfig uses... */
698 if (!(flags & IFF_LOOPBACK) &&
699 (flags & (IFF_BROADCAST | IFF_POINTOPOINT))) {
700 dprintf("Trying to bring up %s\n", de->d_name);
701
702 if (!(dev = add_device(de->d_name)))
703 continue;
704 bringup_one_dev(template, dev);
705 }
706 }
707 closedir(d);
708 return 1;
709 }
710
711 static int check_autoconfig(void)
712 {
713 int ndev = 0, nauto = 0;
714 struct state *s;
715
716 for (s = slist; s; s = s->next) {
717 ndev++;
718 if (s->dev->caps)
719 nauto++;
720 }
721
722 if (ndev == 0) {
723 if (configured == 0) {
724 fprintf(stderr, "%s: no devices to configure\n",
725 progname);
726 longjmp(abort_buf, 1);
727 }
728 }
729
730 return nauto;
731 }
732
733 static void set_vendor_identifier(const char *id)
734 {
735 int len = strlen(id);
736 if (len >= 255) {
737 fprintf(stderr,
738 "%s: invalid vendor class identifier: "
739 "%s\n", progname, id);
740 longjmp(abort_buf, 1);
741 }
742 memcpy(vendor_class_identifier+2, id, len);
743 vendor_class_identifier[0] = 60;
744 vendor_class_identifier[1] = len;
745 vendor_class_identifier_len = len+2;
746 }
747
748 int main(int argc, char *argv[])
749 __attribute__ ((weak, alias("ipconfig_main")));
750
751 int ipconfig_main(int argc, char *argv[])
752 {
753 struct netdev *dev;
754 int c, port;
755 int err = 0;
756
757 /* If progname is set we're invoked from another program */
758 if (!progname) {
759 struct timeval now;
760 progname = argv[0];
761 gettimeofday(&now, NULL);
762 srand48(now.tv_usec ^ (now.tv_sec << 24));
763 }
764
765 if ((err = setjmp(abort_buf)))
766 return err;
767
768 /* Default vendor identifier */
769 set_vendor_identifier("Linux ipconfig");
770
771 do {
772 c = getopt(argc, argv, "c:d:i:onp:t:");
773 if (c == EOF)
774 break;
775
776 switch (c) {
777 case 'c':
778 default_caps = parse_proto(optarg);
779 break;
780 case 'p':
781 port = atoi(optarg);
782 if (port <= 0 || port > USHRT_MAX) {
783 fprintf(stderr,
784 "%s: invalid port number %d\n",
785 progname, port);
786 longjmp(abort_buf, 1);
787 }
788 cfg_local_port = port;
789 cfg_remote_port = cfg_local_port - 1;
790 break;
791 case 't':
792 loop_timeout = atoi(optarg);
793 if (loop_timeout < 0) {
794 fprintf(stderr,
795 "%s: invalid timeout %d\n",
796 progname, loop_timeout);
797 longjmp(abort_buf, 1);
798 }
799 break;
800 case 'i':
801 set_vendor_identifier(optarg);
802 break;
803 case 'o':
804 bringup_first = 1;
805 break;
806 case 'n':
807 do_not_config = 1;
808 break;
809 case 'd':
810 dev = add_device(optarg);
811 if (dev)
812 bringup_device(dev);
813 break;
814 case '?':
815 fprintf(stderr, "%s: invalid option -%c\n",
816 progname, optopt);
817 longjmp(abort_buf, 1);
818 }
819 } while (1);
820
821 for (c = optind; c < argc; c++) {
822 dev = add_device(argv[c]);
823 if (dev)
824 bringup_device(dev);
825 }
826
827 if (check_autoconfig()) {
828 if (cfg_local_port != LOCAL_PORT) {
829 printf("IP-Config: binding source port to %d, "
830 "dest to %d\n",
831 cfg_local_port, cfg_remote_port);
832 }
833 err = loop();
834 }
835
836 return err;
837 }