Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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