Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 17182 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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