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