1 /* $KAME: rrenumd.c,v 1.20 2000/11/08 02:40:53 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD: src/usr.sbin/rrenumd/rrenumd.c,v 1.1.2.4 2001/07/09 09:49:49 ume Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/socket.h> 36 #include <sys/uio.h> 37 #include <sys/time.h> 38 39 #include <string.h> 40 41 #include <net/route.h> 42 43 #include <netinet/in_systm.h> 44 #include <netinet/in.h> 45 #include <netinet/ip.h> 46 #include <netinet/ip6.h> 47 #include <netinet/icmp6.h> 48 49 #include <arpa/inet.h> 50 51 #ifdef IPSEC 52 #include <netinet6/ipsec.h> 53 #endif 54 55 #include <stdio.h> 56 #include <err.h> 57 #include <errno.h> 58 #include <stdlib.h> 59 #include <unistd.h> 60 #include <syslog.h> 61 62 #include "rrenumd.h" 63 64 #define LL_ALLROUTERS "ff02::2" 65 #define SL_ALLROUTERS "ff05::2" 66 67 #define RR_MCHLIM_DEFAULT 64 68 69 #ifndef IN6_IS_SCOPE_LINKLOCAL 70 #define IN6_IS_SCOPE_LINKLOCAL(a) \ 71 ((IN6_IS_ADDR_LINKLOCAL(a)) || \ 72 (IN6_IS_ADDR_MC_LINKLOCAL(a))) 73 #endif /* IN6_IS_SCOPE_LINKLOCAL */ 74 75 struct flags { 76 u_long debug : 1; 77 u_long fg : 1; 78 #ifdef IPSEC 79 #ifdef IPSEC_POLICY_IPSEC 80 u_long policy : 1; 81 #else /* IPSEC_POLICY_IPSEC */ 82 u_long auth : 1; 83 u_long encrypt : 1; 84 #endif /* IPSEC_POLICY_IPSEC */ 85 #endif /*IPSEC*/ 86 }; 87 88 struct msghdr sndmhdr; 89 struct msghdr rcvmhdr; 90 struct sockaddr_in6 from; 91 struct sockaddr_in6 sin6_ll_allrouters; 92 93 int s4, s6; 94 int with_v4dest, with_v6dest; 95 struct in6_addr prefix; /* ADHOC */ 96 int prefixlen = 64; /* ADHOC */ 97 98 extern int parse(FILE **); 99 100 static void show_usage(void); 101 static void init_sin6(struct sockaddr_in6 *, const char *); 102 #if 0 103 static void join_multi(const char *); 104 #endif 105 static void init_globals(void); 106 static void config(FILE **); 107 #ifdef IPSEC_POLICY_IPSEC 108 static void sock6_open(struct flags *, char *); 109 static void sock4_open(struct flags *, char *); 110 #else 111 static void sock6_open(struct flags *); 112 static void sock4_open(struct flags *); 113 #endif 114 static void rrenum_output(struct payload_list *, struct dst_list *); 115 static void rrenum_snd_eachdst(struct payload_list *); 116 #if 0 117 static void rrenum_snd_fullsequence(void); 118 #endif 119 static void rrenum_input(int); 120 121 122 /* Print usage. Don't call this after daemonized. */ 123 static void 124 show_usage(void) 125 { 126 fprintf(stderr, "usage: rrenumd [-c conf_file|-s] [-df" 127 #ifdef IPSEC 128 #ifdef IPSEC_POLICY_IPSEC 129 "] [-P policy" 130 #else /* IPSEC_POLICY_IPSEC */ 131 "AE" 132 #endif /* IPSEC_POLICY_IPSEC */ 133 #endif /* IPSEC */ 134 "]\n"); 135 exit(1); 136 } 137 138 static void 139 init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) 140 { 141 memset(sin6, 0, sizeof(*sin6)); 142 sin6->sin6_len = sizeof(*sin6); 143 sin6->sin6_family = AF_INET6; 144 if (inet_pton(AF_INET6, addr_ascii, &sin6->sin6_addr) != 1) 145 ; /* XXX do something */ 146 } 147 148 #if 0 /* XXX: not necessary ?? */ 149 static void 150 join_multi(const char *addrname) 151 { 152 struct ipv6_mreq mreq; 153 154 if (inet_pton(AF_INET6, addrname, &mreq.ipv6mr_multiaddr.s6_addr) 155 != 1) { 156 syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", 157 __func__); 158 exit(1); 159 } 160 /* ADHOC: currently join only one */ 161 { 162 if ((mreq.ipv6mr_interface = if_nametoindex(ifname)) == 0) { 163 syslog(LOG_ERR, "<%s> ifname %s should be invalid: %s", 164 __func__, ifname, strerror(errno)); 165 exit(1); 166 } 167 if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, 168 &mreq, 169 sizeof(mreq)) < 0) { 170 syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", 171 __func__, ifname, strerror(errno)); 172 exit(1); 173 } 174 } 175 } 176 #endif 177 178 static void 179 init_globals(void) 180 { 181 static struct iovec rcviov; 182 static u_char rprdata[4500]; /* maximal MTU of connected links */ 183 static u_char *rcvcmsgbuf = NULL; 184 static u_char *sndcmsgbuf = NULL; 185 int sndcmsglen, rcvcmsglen; 186 187 /* init ll_allrouters */ 188 init_sin6(&sin6_ll_allrouters, LL_ALLROUTERS); 189 190 /* initialize msghdr for receiving packets */ 191 rcviov.iov_base = (caddr_t)rprdata; 192 rcviov.iov_len = sizeof(rprdata); 193 rcvmhdr.msg_namelen = sizeof(struct sockaddr_in6); 194 rcvmhdr.msg_iov = &rcviov; 195 rcvmhdr.msg_iovlen = 1; 196 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 197 CMSG_SPACE(sizeof(int)); 198 if (rcvcmsgbuf == NULL && 199 (rcvcmsgbuf = (u_char *)malloc(rcvcmsglen)) == NULL) { 200 syslog(LOG_ERR, "<%s>: malloc failed", __func__); 201 exit(1); 202 } 203 rcvmhdr.msg_control = (caddr_t)rcvcmsgbuf; 204 rcvmhdr.msg_controllen = rcvcmsglen; 205 206 /* initialize msghdr for sending packets */ 207 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 208 sndmhdr.msg_iovlen = 1; 209 sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 210 CMSG_SPACE(sizeof(int)); 211 if (sndcmsgbuf == NULL && 212 (sndcmsgbuf = (u_char *)malloc(sndcmsglen)) == NULL) { 213 syslog(LOG_ERR, "<%s>: malloc failed", __func__); 214 exit(1); 215 } 216 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 217 sndmhdr.msg_controllen = sndcmsglen; 218 } 219 220 static void 221 config(FILE **fpp) 222 { 223 struct payload_list *pl; 224 struct iovec *iov; 225 struct icmp6_router_renum *irr; 226 struct rr_pco_match *rpm; 227 228 if (parse(fpp) < 0) { 229 syslog(LOG_ERR, "<%s> parse failed", __func__); 230 exit(1); 231 } 232 233 /* initialize fields not configured by parser */ 234 for (pl = pl_head; pl; pl = pl->pl_next) { 235 iov = (struct iovec *)&pl->pl_sndiov; 236 irr = (struct icmp6_router_renum *)&pl->pl_irr; 237 rpm = (struct rr_pco_match *)&pl->pl_rpm; 238 239 irr->rr_type = ICMP6_ROUTER_RENUMBERING; 240 irr->rr_code = 0; 241 /* 242 * now we don't support multiple PCOs in a rr message. 243 * so segment number is not supported. 244 */ 245 /* TODO: rr flags config in parser */ 246 irr->rr_flags |= ICMP6_RR_FLAGS_SPECSITE; 247 /* TODO: max delay config in parser */ 248 249 /* 250 * means only 1 use_prefix is contained as router-renum-05.txt. 251 * now we don't support multiple PCOs in a rr message, 252 * nor multiple use_prefix in one PCO. 253 */ 254 rpm->rpm_len = 4*1 +3; 255 rpm->rpm_ordinal = 0; 256 iov->iov_base = (caddr_t)irr; 257 iov->iov_len = sizeof(struct icmp6_router_renum) 258 + sizeof(struct rr_pco_match) 259 + sizeof(struct rr_pco_use); 260 } 261 } 262 263 static void 264 sock6_open(struct flags *flags 265 #ifdef IPSEC_POLICY_IPSEC 266 , char *policy 267 #endif /* IPSEC_POLICY_IPSEC */ 268 ) 269 { 270 struct icmp6_filter filt; 271 int on; 272 #ifdef IPSEC 273 #ifndef IPSEC_POLICY_IPSEC 274 int optval; 275 #endif 276 #endif 277 278 if (with_v6dest == 0) 279 return; 280 if (with_v6dest && 281 (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 282 syslog(LOG_ERR, "<%s> socket(v6): %s", __func__, 283 strerror(errno)); 284 exit(1); 285 } 286 287 /* 288 * join all routers multicast addresses. 289 */ 290 #if 0 /* XXX: not necessary ?? */ 291 join_multi(LL_ALLROUTERS); 292 join_multi(SL_ALLROUTERS); 293 #endif 294 295 /* set icmpv6 filter */ 296 ICMP6_FILTER_SETBLOCKALL(&filt); 297 ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); 298 if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 299 sizeof(filt)) < 0) { 300 syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", 301 __func__, strerror(errno)); 302 exit(1); 303 } 304 305 /* specify to tell receiving interface */ 306 on = 1; 307 if (setsockopt(s6, IPPROTO_IPV6, IPV6_PKTINFO, &on, 308 sizeof(on)) < 0) { 309 syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", 310 __func__, strerror(errno)); 311 exit(1); 312 } 313 314 #ifdef IPSEC 315 #ifdef IPSEC_POLICY_IPSEC 316 if (flags->policy) { 317 char *buf; 318 buf = ipsec_set_policy(policy, strlen(policy)); 319 if (buf == NULL) 320 errx(1, "%s", ipsec_strerror()); 321 /* XXX should handle in/out bound policy. */ 322 if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 323 buf, ipsec_get_policylen(buf)) < 0) 324 err(1, "setsockopt(IPV6_IPSEC_POLICY)"); 325 free(buf); 326 } 327 #else /* IPSEC_POLICY_IPSEC */ 328 if (flags->auth) { 329 optval = IPSEC_LEVEL_REQUIRE; 330 if (setsockopt(s6, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, 331 &optval, sizeof(optval)) == -1) { 332 syslog(LOG_ERR, "<%s> IPV6_AUTH_TRANS_LEVEL: %s", 333 __func__, strerror(errno)); 334 exit(1); 335 } 336 } 337 if (flags->encrypt) { 338 optval = IPSEC_LEVEL_REQUIRE; 339 if (setsockopt(s6, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, 340 &optval, sizeof(optval)) == -1) { 341 syslog(LOG_ERR, "<%s> IPV6_ESP_TRANS_LEVEL: %s", 342 __func__, strerror(errno)); 343 exit(1); 344 } 345 } 346 #endif /* IPSEC_POLICY_IPSEC */ 347 #endif /* IPSEC */ 348 349 return; 350 } 351 352 static void 353 sock4_open(struct flags *flags 354 #ifdef IPSEC_POLICY_IPSEC 355 , char *policy 356 #endif /* IPSEC_POLICY_IPSEC */ 357 ) 358 { 359 #ifdef IPSEC 360 #ifndef IPSEC_POLICY_IPSEC 361 int optval; 362 #endif 363 #endif 364 365 if (with_v4dest == 0) 366 return; 367 if ((s4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 368 syslog(LOG_ERR, "<%s> socket(v4): %s", __func__, 369 strerror(errno)); 370 exit(1); 371 } 372 373 #if 0 /* XXX: not necessary ?? */ 374 /* 375 * join all routers multicast addresses. 376 */ 377 some_join_function(); 378 #endif 379 380 #ifdef IPSEC 381 #ifdef IPSEC_POLICY_IPSEC 382 if (flags->policy) { 383 char *buf; 384 buf = ipsec_set_policy(policy, strlen(policy)); 385 if (buf == NULL) 386 errx(1, "%s", ipsec_strerror()); 387 /* XXX should handle in/out bound policy. */ 388 if (setsockopt(s4, IPPROTO_IP, IP_IPSEC_POLICY, 389 buf, ipsec_get_policylen(buf)) < 0) 390 err(1, "setsockopt(IP_IPSEC_POLICY)"); 391 free(buf); 392 } 393 #else /* IPSEC_POLICY_IPSEC */ 394 if (flags->auth) { 395 optval = IPSEC_LEVEL_REQUIRE; 396 if (setsockopt(s4, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, 397 &optval, sizeof(optval)) == -1) { 398 syslog(LOG_ERR, "<%s> IP_AUTH_TRANS_LEVEL: %s", 399 __func__, strerror(errno)); 400 exit(1); 401 } 402 } 403 if (flags->encrypt) { 404 optval = IPSEC_LEVEL_REQUIRE; 405 if (setsockopt(s4, IPPROTO_IP, IP_ESP_TRANS_LEVEL, 406 &optval, sizeof(optval)) == -1) { 407 syslog(LOG_ERR, "<%s> IP_ESP_TRANS_LEVEL: %s", 408 __func__, strerror(errno)); 409 exit(1); 410 } 411 } 412 #endif /* IPSEC_POLICY_IPSEC */ 413 #endif /* IPSEC */ 414 415 return; 416 } 417 418 static void 419 rrenum_output(struct payload_list *pl, struct dst_list *dl) 420 { 421 int i, msglen = 0; 422 struct cmsghdr *cm; 423 struct in6_pktinfo *pi; 424 struct sockaddr_in6 *sin6 = NULL; 425 426 sndmhdr.msg_name = (caddr_t)dl->dl_dst; 427 if (dl->dl_dst->sa_family == AF_INET6) 428 sin6 = (struct sockaddr_in6 *)dl->dl_dst; 429 430 if (sin6 != NULL && 431 IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 432 int hoplimit = RR_MCHLIM_DEFAULT; 433 434 cm = CMSG_FIRSTHDR(&sndmhdr); 435 /* specify the outgoing interface */ 436 cm->cmsg_level = IPPROTO_IPV6; 437 cm->cmsg_type = IPV6_PKTINFO; 438 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 439 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 440 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 441 pi->ipi6_ifindex = sin6->sin6_scope_id; 442 msglen += CMSG_LEN(sizeof(struct in6_pktinfo)); 443 444 /* specify the hop limit of the packet if dest is link local */ 445 /* not defined by router-renum-05.txt, but maybe its OK */ 446 cm = CMSG_NXTHDR(&sndmhdr, cm); 447 cm->cmsg_level = IPPROTO_IPV6; 448 cm->cmsg_type = IPV6_HOPLIMIT; 449 cm->cmsg_len = CMSG_LEN(sizeof(int)); 450 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 451 msglen += CMSG_LEN(sizeof(int)); 452 } 453 sndmhdr.msg_controllen = msglen; 454 if (sndmhdr.msg_controllen == 0) 455 sndmhdr.msg_control = 0; 456 457 sndmhdr.msg_iov = &pl->pl_sndiov; 458 i = sendmsg(dl->dl_dst->sa_family == AF_INET ? s4 : s6, &sndmhdr, 0); 459 460 if (i < 0 || i != sndmhdr.msg_iov->iov_len) 461 syslog(LOG_ERR, "<%s> sendmsg: %s", __func__, 462 strerror(errno)); 463 } 464 465 static void 466 rrenum_snd_eachdst(struct payload_list *pl) 467 { 468 struct dst_list *dl; 469 470 for (dl = dl_head; dl; dl = dl->dl_next) { 471 rrenum_output(pl, dl); 472 } 473 } 474 475 #if 0 476 static void 477 rrenum_snd_fullsequence(void) 478 { 479 struct payload_list *pl; 480 481 for (pl = pl_head; pl; pl = pl->pl_next) { 482 rrenum_snd_eachdst(pl); 483 } 484 } 485 #endif 486 487 static void 488 rrenum_input(int s) 489 { 490 int i; 491 struct icmp6_router_renum *rr; 492 493 /* get message */ 494 if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { 495 syslog(LOG_ERR, "<%s> recvmsg: %s", __func__, 496 strerror(errno)); 497 return; 498 } 499 if (s == s4) 500 i -= sizeof(struct ip); 501 if (i < sizeof(struct icmp6_router_renum)) { 502 syslog(LOG_ERR, "<%s> packet size(%d) is too short", 503 __func__, i); 504 return; 505 } 506 if (s == s4) { 507 struct ip *ip = (struct ip *)rcvmhdr.msg_iov->iov_base; 508 509 rr = (struct icmp6_router_renum *)(ip + 1); 510 } else /* s == s6 */ 511 rr = (struct icmp6_router_renum *)rcvmhdr.msg_iov->iov_base; 512 513 switch(rr->rr_code) { 514 case ICMP6_ROUTER_RENUMBERING_COMMAND: 515 /* COMMAND will be processed by rtadvd */ 516 break; 517 case ICMP6_ROUTER_RENUMBERING_RESULT: 518 /* TODO: receiving result message */ 519 break; 520 default: 521 syslog(LOG_ERR, "<%s> received unknown code %d", 522 __func__, rr->rr_code); 523 break; 524 } 525 } 526 527 int 528 main(int argc, char *argv[]) 529 { 530 FILE *fp = stdin; 531 fd_set fdset; 532 struct timeval timeout; 533 int ch, i, maxfd = 0, send_counter = 0; 534 struct flags flags; 535 struct payload_list *pl; 536 #ifdef IPSEC_POLICY_IPSEC 537 char *policy = NULL; 538 #endif 539 540 memset(&flags, 0, sizeof(flags)); 541 openlog("rrenumd", LOG_PID, LOG_DAEMON); 542 543 /* get options */ 544 while ((ch = getopt(argc, argv, "c:sdf" 545 #ifdef IPSEC 546 #ifdef IPSEC_POLICY_IPSEC 547 "P:" 548 #else /* IPSEC_POLICY_IPSEC */ 549 "AE" 550 #endif /* IPSEC_POLICY_IPSEC */ 551 #endif /* IPSEC */ 552 )) != -1){ 553 switch (ch) { 554 case 'c': 555 if((fp = fopen(optarg, "r")) == NULL) { 556 syslog(LOG_ERR, 557 "<%s> config file %s open failed", 558 __func__, optarg); 559 exit(1); 560 } 561 break; 562 case 's': 563 fp = stdin; 564 break; 565 case 'd': 566 flags.debug = 1; 567 break; 568 case 'f': 569 flags.fg = 1; 570 break; 571 #ifdef IPSEC 572 #ifdef IPSEC_POLICY_IPSEC 573 case 'P': 574 flags.policy = 1; 575 policy = strdup(optarg); 576 break; 577 #else /* IPSEC_POLICY_IPSEC */ 578 case 'A': 579 flags.auth = 1; 580 break; 581 case 'E': 582 flags.encrypt = 1; 583 break; 584 #endif /* IPSEC_POLICY_IPSEC */ 585 #endif /*IPSEC*/ 586 default: 587 show_usage(); 588 } 589 } 590 argc -= optind; 591 argv += optind; 592 593 /* set log level */ 594 if (flags.debug == 0) 595 setlogmask(LOG_UPTO(LOG_ERR)); 596 if (flags.debug == 1) 597 setlogmask(LOG_UPTO(LOG_INFO)); 598 599 /* init global variables */ 600 init_globals(); 601 602 config(&fp); 603 604 sock6_open(&flags 605 #ifdef IPSEC_POLICY_IPSEC 606 , policy 607 #endif /* IPSEC_POLICY_IPSEC */ 608 ); 609 sock4_open(&flags 610 #ifdef IPSEC_POLICY_IPSEC 611 , policy 612 #endif /* IPSEC_POLICY_IPSEC */ 613 ); 614 615 if (!flags.fg) 616 daemon(0, 0); 617 618 FD_ZERO(&fdset); 619 if (with_v6dest) { 620 FD_SET(s6, &fdset); 621 if (s6 > maxfd) 622 maxfd = s6; 623 } 624 if (with_v4dest) { 625 FD_SET(s4, &fdset); 626 if (s4 > maxfd) 627 maxfd = s4; 628 } 629 630 /* ADHOC: timeout each 30seconds */ 631 memset(&timeout, 0, sizeof(timeout)); 632 633 /* init temporary payload_list and send_counter*/ 634 pl = pl_head; 635 send_counter = retry + 1; 636 while (1) { 637 struct fd_set select_fd = fdset; /* reinitialize */ 638 639 if ((i = select(maxfd + 1, &select_fd, NULL, NULL, 640 &timeout)) < 0){ 641 syslog(LOG_ERR, "<%s> select: %s", 642 __func__, strerror(errno)); 643 continue; 644 } 645 if (i == 0) { /* timeout */ 646 if (pl == NULL) 647 exit(0); 648 rrenum_snd_eachdst(pl); 649 send_counter--; 650 timeout.tv_sec = 30; 651 if (send_counter == 0) { 652 timeout.tv_sec = 0; 653 pl = pl->pl_next; 654 send_counter = retry + 1; 655 } 656 } 657 if (FD_ISSET(s4, &select_fd)) 658 rrenum_input(s4); 659 if (FD_ISSET(s6, &select_fd)) 660 rrenum_input(s6); 661 } 662 } 663