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 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 <netipsec/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 int main(int, char *[]); 121 122 123 /* Print usage. Don't call this after daemonized. */ 124 static void 125 show_usage() 126 { 127 fprintf(stderr, "usage: rrenumd [-c conf_file|-s] [-df" 128 #ifdef IPSEC 129 #ifdef IPSEC_POLICY_IPSEC 130 "] [-P policy" 131 #else /* IPSEC_POLICY_IPSEC */ 132 "AE" 133 #endif /* IPSEC_POLICY_IPSEC */ 134 #endif /* IPSEC */ 135 "]\n"); 136 exit(1); 137 } 138 139 static void 140 init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) 141 { 142 memset(sin6, 0, sizeof(*sin6)); 143 sin6->sin6_len = sizeof(*sin6); 144 sin6->sin6_family = AF_INET6; 145 if (inet_pton(AF_INET6, addr_ascii, &sin6->sin6_addr) != 1) 146 ; /* XXX do something */ 147 } 148 149 #if 0 /* XXX: not necessary ?? */ 150 static void 151 join_multi(const char *addrname) 152 { 153 struct ipv6_mreq mreq; 154 155 if (inet_pton(AF_INET6, addrname, &mreq.ipv6mr_multiaddr.s6_addr) 156 != 1) { 157 syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", 158 __func__); 159 exit(1); 160 } 161 /* ADHOC: currently join only one */ 162 { 163 if ((mreq.ipv6mr_interface = if_nametoindex(ifname)) == 0) { 164 syslog(LOG_ERR, "<%s> ifname %s should be invalid: %s", 165 __func__, ifname, strerror(errno)); 166 exit(1); 167 } 168 if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, 169 &mreq, 170 sizeof(mreq)) < 0) { 171 syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", 172 __func__, ifname, strerror(errno)); 173 exit(1); 174 } 175 } 176 } 177 #endif 178 179 static void 180 init_globals() 181 { 182 static struct iovec rcviov; 183 static u_char rprdata[4500]; /* maximal MTU of connected links */ 184 static u_char *rcvcmsgbuf = NULL; 185 static u_char *sndcmsgbuf = NULL; 186 int sndcmsglen, rcvcmsglen; 187 188 /* init ll_allrouters */ 189 init_sin6(&sin6_ll_allrouters, LL_ALLROUTERS); 190 191 /* initialize msghdr for receiving packets */ 192 rcviov.iov_base = (caddr_t)rprdata; 193 rcviov.iov_len = sizeof(rprdata); 194 rcvmhdr.msg_namelen = sizeof(struct sockaddr_in6); 195 rcvmhdr.msg_iov = &rcviov; 196 rcvmhdr.msg_iovlen = 1; 197 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 198 CMSG_SPACE(sizeof(int)); 199 if (rcvcmsgbuf == NULL && 200 (rcvcmsgbuf = (u_char *)malloc(rcvcmsglen)) == NULL) { 201 syslog(LOG_ERR, "<%s>: malloc failed", __func__); 202 exit(1); 203 } 204 rcvmhdr.msg_control = (caddr_t)rcvcmsgbuf; 205 rcvmhdr.msg_controllen = rcvcmsglen; 206 207 /* initialize msghdr for sending packets */ 208 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 209 sndmhdr.msg_iovlen = 1; 210 sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 211 CMSG_SPACE(sizeof(int)); 212 if (sndcmsgbuf == NULL && 213 (sndcmsgbuf = (u_char *)malloc(sndcmsglen)) == NULL) { 214 syslog(LOG_ERR, "<%s>: malloc failed", __func__); 215 exit(1); 216 } 217 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 218 sndmhdr.msg_controllen = sndcmsglen; 219 } 220 221 static void 222 config(FILE **fpp) 223 { 224 struct payload_list *pl; 225 struct iovec *iov; 226 struct icmp6_router_renum *irr; 227 struct rr_pco_match *rpm; 228 229 if (parse(fpp) < 0) { 230 syslog(LOG_ERR, "<%s> parse failed", __func__); 231 exit(1); 232 } 233 234 /* initialize fields not configured by parser */ 235 for (pl = pl_head; pl; pl = pl->pl_next) { 236 iov = (struct iovec *)&pl->pl_sndiov; 237 irr = (struct icmp6_router_renum *)&pl->pl_irr; 238 rpm = (struct rr_pco_match *)&pl->pl_rpm; 239 240 irr->rr_type = ICMP6_ROUTER_RENUMBERING; 241 irr->rr_code = 0; 242 /* 243 * now we don't support multiple PCOs in a rr message. 244 * so segment number is not supported. 245 */ 246 /* TODO: rr flags config in parser */ 247 irr->rr_flags |= ICMP6_RR_FLAGS_SPECSITE; 248 /* TODO: max delay config in parser */ 249 250 /* 251 * means only 1 use_prefix is contained as router-renum-05.txt. 252 * now we don't support multiple PCOs in a rr message, 253 * nor multiple use_prefix in one PCO. 254 */ 255 rpm->rpm_len = 4*1 +3; 256 rpm->rpm_ordinal = 0; 257 iov->iov_base = (caddr_t)irr; 258 iov->iov_len = sizeof(struct icmp6_router_renum) 259 + sizeof(struct rr_pco_match) 260 + sizeof(struct rr_pco_use); 261 } 262 } 263 264 static void 265 sock6_open(struct flags *flags 266 #ifdef IPSEC_POLICY_IPSEC 267 , char *policy 268 #endif /* IPSEC_POLICY_IPSEC */ 269 ) 270 { 271 struct icmp6_filter filt; 272 int on; 273 #ifdef IPSEC 274 #ifndef IPSEC_POLICY_IPSEC 275 int optval; 276 #endif 277 #endif 278 279 if (with_v6dest == 0) 280 return; 281 if (with_v6dest && 282 (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 283 syslog(LOG_ERR, "<%s> socket(v6): %s", __func__, 284 strerror(errno)); 285 exit(1); 286 } 287 288 /* 289 * join all routers multicast addresses. 290 */ 291 #if 0 /* XXX: not necessary ?? */ 292 join_multi(LL_ALLROUTERS); 293 join_multi(SL_ALLROUTERS); 294 #endif 295 296 /* set icmpv6 filter */ 297 ICMP6_FILTER_SETBLOCKALL(&filt); 298 ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); 299 if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 300 sizeof(filt)) < 0) { 301 syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", 302 __func__, strerror(errno)); 303 exit(1); 304 } 305 306 /* specify to tell receiving interface */ 307 on = 1; 308 if (setsockopt(s6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 309 sizeof(on)) < 0) { 310 syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", 311 __func__, strerror(errno)); 312 exit(1); 313 } 314 315 #ifdef IPSEC 316 #ifdef IPSEC_POLICY_IPSEC 317 if (flags->policy) { 318 char *buf; 319 buf = ipsec_set_policy(policy, strlen(policy)); 320 if (buf == NULL) 321 errx(1, "%s", ipsec_strerror()); 322 /* XXX should handle in/out bound policy. */ 323 if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 324 buf, ipsec_get_policylen(buf)) < 0) 325 err(1, "setsockopt(IPV6_IPSEC_POLICY)"); 326 free(buf); 327 } 328 #else /* IPSEC_POLICY_IPSEC */ 329 if (flags->auth) { 330 optval = IPSEC_LEVEL_REQUIRE; 331 if (setsockopt(s6, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, 332 &optval, sizeof(optval)) == -1) { 333 syslog(LOG_ERR, "<%s> IPV6_AUTH_TRANS_LEVEL: %s", 334 __func__, strerror(errno)); 335 exit(1); 336 } 337 } 338 if (flags->encrypt) { 339 optval = IPSEC_LEVEL_REQUIRE; 340 if (setsockopt(s6, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, 341 &optval, sizeof(optval)) == -1) { 342 syslog(LOG_ERR, "<%s> IPV6_ESP_TRANS_LEVEL: %s", 343 __func__, strerror(errno)); 344 exit(1); 345 } 346 } 347 #endif /* IPSEC_POLICY_IPSEC */ 348 #endif /* IPSEC */ 349 } 350 351 static void 352 sock4_open(struct flags *flags 353 #ifdef IPSEC_POLICY_IPSEC 354 , char *policy 355 #endif /* IPSEC_POLICY_IPSEC */ 356 ) 357 { 358 #ifdef IPSEC 359 #ifndef IPSEC_POLICY_IPSEC 360 int optval; 361 #endif 362 #endif 363 364 if (with_v4dest == 0) 365 return; 366 if ((s4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 367 syslog(LOG_ERR, "<%s> socket(v4): %s", __func__, 368 strerror(errno)); 369 exit(1); 370 } 371 372 #if 0 /* XXX: not necessary ?? */ 373 /* 374 * join all routers multicast addresses. 375 */ 376 some_join_function(); 377 #endif 378 379 #ifdef IPSEC 380 #ifdef IPSEC_POLICY_IPSEC 381 if (flags->policy) { 382 char *buf; 383 buf = ipsec_set_policy(policy, strlen(policy)); 384 if (buf == NULL) 385 errx(1, "%s", ipsec_strerror()); 386 /* XXX should handle in/out bound policy. */ 387 if (setsockopt(s4, IPPROTO_IP, IP_IPSEC_POLICY, 388 buf, ipsec_get_policylen(buf)) < 0) 389 err(1, "setsockopt(IP_IPSEC_POLICY)"); 390 free(buf); 391 } 392 #else /* IPSEC_POLICY_IPSEC */ 393 if (flags->auth) { 394 optval = IPSEC_LEVEL_REQUIRE; 395 if (setsockopt(s4, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, 396 &optval, sizeof(optval)) == -1) { 397 syslog(LOG_ERR, "<%s> IP_AUTH_TRANS_LEVEL: %s", 398 __func__, strerror(errno)); 399 exit(1); 400 } 401 } 402 if (flags->encrypt) { 403 optval = IPSEC_LEVEL_REQUIRE; 404 if (setsockopt(s4, IPPROTO_IP, IP_ESP_TRANS_LEVEL, 405 &optval, sizeof(optval)) == -1) { 406 syslog(LOG_ERR, "<%s> IP_ESP_TRANS_LEVEL: %s", 407 __func__, strerror(errno)); 408 exit(1); 409 } 410 } 411 #endif /* IPSEC_POLICY_IPSEC */ 412 #endif /* IPSEC */ 413 } 414 415 static void 416 rrenum_output(struct payload_list *pl, struct dst_list *dl) 417 { 418 int i, msglen = 0; 419 struct cmsghdr *cm; 420 struct in6_pktinfo *pi; 421 struct sockaddr_in6 *sin6 = NULL; 422 423 sndmhdr.msg_name = (caddr_t)dl->dl_dst; 424 if (dl->dl_dst->sa_family == AF_INET6) 425 sin6 = (struct sockaddr_in6 *)dl->dl_dst; 426 427 if (sin6 != NULL && 428 IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 429 int hoplimit = RR_MCHLIM_DEFAULT; 430 431 cm = CMSG_FIRSTHDR(&sndmhdr); 432 /* specify the outgoing interface */ 433 cm->cmsg_level = IPPROTO_IPV6; 434 cm->cmsg_type = IPV6_PKTINFO; 435 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 436 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 437 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 438 pi->ipi6_ifindex = sin6->sin6_scope_id; 439 msglen += CMSG_LEN(sizeof(struct in6_pktinfo)); 440 441 /* specify the hop limit of the packet if dest is link local */ 442 /* not defined by router-renum-05.txt, but maybe its OK */ 443 cm = CMSG_NXTHDR(&sndmhdr, cm); 444 cm->cmsg_level = IPPROTO_IPV6; 445 cm->cmsg_type = IPV6_HOPLIMIT; 446 cm->cmsg_len = CMSG_LEN(sizeof(int)); 447 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 448 msglen += CMSG_LEN(sizeof(int)); 449 } 450 sndmhdr.msg_controllen = msglen; 451 if (sndmhdr.msg_controllen == 0) 452 sndmhdr.msg_control = 0; 453 454 sndmhdr.msg_iov = &pl->pl_sndiov; 455 i = sendmsg(dl->dl_dst->sa_family == AF_INET ? s4 : s6, &sndmhdr, 0); 456 457 if (i < 0 || i != sndmhdr.msg_iov->iov_len) 458 syslog(LOG_ERR, "<%s> sendmsg: %s", __func__, 459 strerror(errno)); 460 } 461 462 static void 463 rrenum_snd_eachdst(struct payload_list *pl) 464 { 465 struct dst_list *dl; 466 467 for (dl = dl_head; dl; dl = dl->dl_next) { 468 rrenum_output(pl, dl); 469 } 470 } 471 472 #if 0 473 static void 474 rrenum_snd_fullsequence() 475 { 476 struct payload_list *pl; 477 478 for (pl = pl_head; pl; pl = pl->pl_next) { 479 rrenum_snd_eachdst(pl); 480 } 481 } 482 #endif 483 484 static void 485 rrenum_input(int s) 486 { 487 int i; 488 struct icmp6_router_renum *rr; 489 490 /* get message */ 491 if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { 492 syslog(LOG_ERR, "<%s> recvmsg: %s", __func__, 493 strerror(errno)); 494 return; 495 } 496 if (s == s4) 497 i -= sizeof(struct ip); 498 if (i < sizeof(struct icmp6_router_renum)) { 499 syslog(LOG_ERR, "<%s> packet size(%d) is too short", 500 __func__, i); 501 return; 502 } 503 if (s == s4) { 504 struct ip *ip = (struct ip *)rcvmhdr.msg_iov->iov_base; 505 506 rr = (struct icmp6_router_renum *)(ip + 1); 507 } else /* s == s6 */ 508 rr = (struct icmp6_router_renum *)rcvmhdr.msg_iov->iov_base; 509 510 switch(rr->rr_code) { 511 case ICMP6_ROUTER_RENUMBERING_COMMAND: 512 /* COMMAND will be processed by rtadvd */ 513 break; 514 case ICMP6_ROUTER_RENUMBERING_RESULT: 515 /* TODO: receiving result message */ 516 break; 517 default: 518 syslog(LOG_ERR, "<%s> received unknown code %d", 519 __func__, rr->rr_code); 520 break; 521 } 522 } 523 524 int 525 main(int argc, char *argv[]) 526 { 527 FILE *fp = stdin; 528 fd_set fdset; 529 struct timeval timeout; 530 int ch, i, maxfd = 0, send_counter = 0; 531 struct flags flags; 532 struct payload_list *pl; 533 #ifdef IPSEC_POLICY_IPSEC 534 char *policy = NULL; 535 #endif 536 537 memset(&flags, 0, sizeof(flags)); 538 openlog("rrenumd", LOG_PID, LOG_DAEMON); 539 540 /* get options */ 541 while ((ch = getopt(argc, argv, "c:sdf" 542 #ifdef IPSEC 543 #ifdef IPSEC_POLICY_IPSEC 544 "P:" 545 #else /* IPSEC_POLICY_IPSEC */ 546 "AE" 547 #endif /* IPSEC_POLICY_IPSEC */ 548 #endif /* IPSEC */ 549 )) != -1){ 550 switch (ch) { 551 case 'c': 552 if((fp = fopen(optarg, "r")) == NULL) { 553 syslog(LOG_ERR, 554 "<%s> config file %s open failed", 555 __func__, optarg); 556 exit(1); 557 } 558 break; 559 case 's': 560 fp = stdin; 561 break; 562 case 'd': 563 flags.debug = 1; 564 break; 565 case 'f': 566 flags.fg = 1; 567 break; 568 #ifdef IPSEC 569 #ifdef IPSEC_POLICY_IPSEC 570 case 'P': 571 flags.policy = 1; 572 policy = strdup(optarg); 573 break; 574 #else /* IPSEC_POLICY_IPSEC */ 575 case 'A': 576 flags.auth = 1; 577 break; 578 case 'E': 579 flags.encrypt = 1; 580 break; 581 #endif /* IPSEC_POLICY_IPSEC */ 582 #endif /*IPSEC*/ 583 default: 584 show_usage(); 585 } 586 } 587 argc -= optind; 588 argv += optind; 589 590 /* set log level */ 591 if (flags.debug == 0) 592 (void)setlogmask(LOG_UPTO(LOG_ERR)); 593 if (flags.debug == 1) 594 (void)setlogmask(LOG_UPTO(LOG_INFO)); 595 596 /* init global variables */ 597 init_globals(); 598 599 config(&fp); 600 601 sock6_open(&flags 602 #ifdef IPSEC_POLICY_IPSEC 603 , policy 604 #endif /* IPSEC_POLICY_IPSEC */ 605 ); 606 sock4_open(&flags 607 #ifdef IPSEC_POLICY_IPSEC 608 , policy 609 #endif /* IPSEC_POLICY_IPSEC */ 610 ); 611 612 if (!flags.fg) 613 daemon(0, 0); 614 615 FD_ZERO(&fdset); 616 if (with_v6dest) { 617 FD_SET(s6, &fdset); 618 if (s6 > maxfd) 619 maxfd = s6; 620 } 621 if (with_v4dest) { 622 FD_SET(s4, &fdset); 623 if (s4 > maxfd) 624 maxfd = s4; 625 } 626 627 /* ADHOC: timeout each 30seconds */ 628 memset(&timeout, 0, sizeof(timeout)); 629 630 /* init temporary payload_list and send_counter*/ 631 pl = pl_head; 632 send_counter = retry + 1; 633 while (1) { 634 struct fd_set select_fd = fdset; /* reinitialize */ 635 636 if ((i = select(maxfd + 1, &select_fd, NULL, NULL, 637 &timeout)) < 0){ 638 syslog(LOG_ERR, "<%s> select: %s", 639 __func__, strerror(errno)); 640 continue; 641 } 642 if (i == 0) { /* timeout */ 643 if (pl == NULL) 644 exit(0); 645 rrenum_snd_eachdst(pl); 646 send_counter--; 647 timeout.tv_sec = 30; 648 if (send_counter == 0) { 649 timeout.tv_sec = 0; 650 pl = pl->pl_next; 651 send_counter = retry + 1; 652 } 653 } 654 if (FD_ISSET(s4, &select_fd)) 655 rrenum_input(s4); 656 if (FD_ISSET(s6, &select_fd)) 657 rrenum_input(s6); 658 } 659 } 660