Magellan Linux

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