1 1.2 darrenr /* $NetBSD: ipfsyncd.c,v 1.2 2012/07/22 14:27:51 darrenr Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.2 darrenr * Copyright (C) 2012 by Darren Reed. 5 1.1 christos * 6 1.1 christos * See the IPFILTER.LICENCE file for details on licencing. 7 1.1 christos */ 8 1.1 christos #if !defined(lint) 9 1.1 christos static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 10 1.2 darrenr static const char rcsid[] = "@(#)Id: ipfsyncd.c,v 1.1.1.2 2012/07/22 13:44:55 darrenr Exp $"; 11 1.1 christos #endif 12 1.1 christos #include <sys/types.h> 13 1.1 christos #include <sys/time.h> 14 1.1 christos #include <sys/socket.h> 15 1.1 christos #include <sys/ioctl.h> 16 1.1 christos #include <sys/sockio.h> 17 1.1 christos #include <sys/errno.h> 18 1.1 christos 19 1.1 christos #include <netinet/in.h> 20 1.1 christos #include <net/if.h> 21 1.1 christos 22 1.1 christos #include <arpa/inet.h> 23 1.1 christos 24 1.1 christos #include <stdio.h> 25 1.1 christos #include <stdlib.h> 26 1.1 christos #include <fcntl.h> 27 1.1 christos #include <unistd.h> 28 1.1 christos #include <string.h> 29 1.1 christos #include <syslog.h> 30 1.1 christos #include <signal.h> 31 1.1 christos 32 1.1 christos #include "ipf.h" 33 1.1 christos #include "opts.h" 34 1.1 christos 35 1.1 christos 36 1.1 christos #define R_IO_ERROR -1 37 1.1 christos #define R_OKAY 0 38 1.1 christos #define R_MORE 1 39 1.1 christos #define R_SKIP 2 40 1.1 christos #if defined(sun) && !defined(SOLARIS2) 41 1.1 christos # define STRERROR(x) sys_errlist[x] 42 1.1 christos extern char *sys_errlist[]; 43 1.1 christos #else 44 1.1 christos # define STRERROR(x) strerror(x) 45 1.1 christos #endif 46 1.1 christos 47 1.1 christos 48 1.1 christos int main __P((int, char *[])); 49 1.1 christos void usage __P((char *)); 50 1.1 christos void printsynchdr __P((synchdr_t *)); 51 1.1 christos void printtable __P((int)); 52 1.1 christos void printsmcproto __P((char *)); 53 1.1 christos void printcommand __P((int)); 54 1.1 christos int do_kbuff __P((int, char *, int *)); 55 1.1 christos int do_packet __P((int, char *)); 56 1.1 christos int buildsocket __P((char *, struct sockaddr_in *)); 57 1.1 christos void do_io __P((void)); 58 1.1 christos void handleterm __P((int)); 59 1.1 christos 60 1.1 christos int terminate = 0; 61 1.1 christos int igmpfd = -1; 62 1.1 christos int nfd = -1; 63 1.1 christos int lfd = -1; 64 1.1 christos int opts = 0; 65 1.1 christos 66 1.1 christos void 67 1.1 christos usage(progname) 68 1.1 christos char *progname; 69 1.1 christos { 70 1.1 christos fprintf(stderr, 71 1.1 christos "Usage: %s [-d] [-p port] [-i address] -I <interface>\n", 72 1.1 christos progname); 73 1.1 christos } 74 1.1 christos 75 1.1 christos void 76 1.1 christos handleterm(sig) 77 1.1 christos int sig; 78 1.1 christos { 79 1.1 christos terminate = sig; 80 1.1 christos } 81 1.1 christos 82 1.1 christos 83 1.1 christos /* should be large enough to hold header + any datatype */ 84 1.1 christos #define BUFFERLEN 1400 85 1.1 christos 86 1.1 christos int 87 1.1 christos main(argc, argv) 88 1.1 christos int argc; 89 1.1 christos char *argv[]; 90 1.1 christos { 91 1.1 christos struct sockaddr_in sin; 92 1.1 christos char *interface; 93 1.1 christos char *progname; 94 1.1 christos int opt, tries; 95 1.1 christos 96 1.1 christos progname = strrchr(argv[0], '/'); 97 1.1 christos if (progname) { 98 1.1 christos progname++; 99 1.1 christos } else { 100 1.1 christos progname = argv[0]; 101 1.1 christos } 102 1.1 christos 103 1.1 christos opts = 0; 104 1.1 christos tries = 0; 105 1.1 christos interface = NULL; 106 1.1 christos 107 1.1 christos bzero((char *)&sin, sizeof(sin)); 108 1.1 christos sin.sin_family = AF_INET; 109 1.1 christos sin.sin_port = htons(0xaf6c); 110 1.1 christos sin.sin_addr.s_addr = htonl(INADDR_UNSPEC_GROUP | 0x697066); 111 1.1 christos 112 1.1 christos while ((opt = getopt(argc, argv, "di:I:p:")) != -1) 113 1.1 christos switch (opt) 114 1.1 christos { 115 1.1 christos case 'd' : 116 1.1 christos debuglevel++; 117 1.1 christos break; 118 1.1 christos case 'I' : 119 1.1 christos interface = optarg; 120 1.1 christos break; 121 1.1 christos case 'i' : 122 1.1 christos sin.sin_addr.s_addr = inet_addr(optarg); 123 1.1 christos break; 124 1.1 christos case 'p' : 125 1.1 christos sin.sin_port = htons(atoi(optarg)); 126 1.1 christos break; 127 1.1 christos } 128 1.1 christos 129 1.1 christos if (interface == NULL) { 130 1.1 christos usage(progname); 131 1.1 christos exit(1); 132 1.1 christos } 133 1.1 christos 134 1.1 christos if (!debuglevel) { 135 1.1 christos 136 1.1 christos #if BSD >= 199306 137 1.1 christos daemon(0, 0); 138 1.1 christos #else 139 1.1 christos int fd = open("/dev/null", O_RDWR); 140 1.1 christos 141 1.1 christos switch (fork()) 142 1.1 christos { 143 1.1 christos case 0 : 144 1.1 christos break; 145 1.1 christos 146 1.1 christos case -1 : 147 1.1 christos fprintf(stderr, "%s: fork() failed: %s\n", 148 1.1 christos argv[0], STRERROR(errno)); 149 1.1 christos exit(1); 150 1.1 christos /* NOTREACHED */ 151 1.1 christos 152 1.1 christos default : 153 1.1 christos exit(0); 154 1.1 christos /* NOTREACHED */ 155 1.1 christos } 156 1.1 christos 157 1.1 christos dup2(fd, 0); 158 1.1 christos dup2(fd, 1); 159 1.1 christos dup2(fd, 2); 160 1.1 christos close(fd); 161 1.1 christos 162 1.1 christos setsid(); 163 1.1 christos #endif 164 1.1 christos } 165 1.1 christos 166 1.1 christos signal(SIGHUP, handleterm); 167 1.1 christos signal(SIGINT, handleterm); 168 1.1 christos signal(SIGTERM, handleterm); 169 1.1 christos 170 1.1 christos openlog(progname, LOG_PID, LOG_SECURITY); 171 1.1 christos 172 1.1 christos while (!terminate) { 173 1.1 christos if (lfd != -1) { 174 1.1 christos close(lfd); 175 1.1 christos lfd = -1; 176 1.1 christos } 177 1.1 christos if (nfd != -1) { 178 1.1 christos close(nfd); 179 1.1 christos nfd = -1; 180 1.1 christos } 181 1.1 christos if (igmpfd != -1) { 182 1.1 christos close(igmpfd); 183 1.1 christos igmpfd = -1; 184 1.1 christos } 185 1.1 christos 186 1.1 christos if (buildsocket(interface, &sin) == -1) 187 1.1 christos goto tryagain; 188 1.1 christos 189 1.1 christos lfd = open(IPSYNC_NAME, O_RDWR); 190 1.1 christos if (lfd == -1) { 191 1.1 christos syslog(LOG_ERR, "open(%s):%m", IPSYNC_NAME); 192 1.1 christos debug(1, "open(%s): %s\n", IPSYNC_NAME, 193 1.1 christos STRERROR(errno)); 194 1.1 christos goto tryagain; 195 1.1 christos } 196 1.1 christos 197 1.1 christos tries = -1; 198 1.1 christos do_io(); 199 1.1 christos tryagain: 200 1.1 christos tries++; 201 1.1 christos syslog(LOG_INFO, "retry in %d seconds", 1 << tries); 202 1.1 christos debug(1, "wait %d seconds\n", 1 << tries); 203 1.1 christos sleep(1 << tries); 204 1.1 christos } 205 1.1 christos 206 1.1 christos 207 1.1 christos /* terminate */ 208 1.1 christos if (lfd != -1) 209 1.1 christos close(lfd); 210 1.1 christos if (nfd != -1) 211 1.1 christos close(nfd); 212 1.1 christos 213 1.1 christos syslog(LOG_ERR, "signal %d received, exiting...", terminate); 214 1.1 christos debug(1, "signal %d received, exiting...", terminate); 215 1.1 christos 216 1.1 christos exit(1); 217 1.1 christos } 218 1.1 christos 219 1.1 christos 220 1.1 christos void 221 1.1 christos do_io() 222 1.1 christos { 223 1.1 christos char nbuff[BUFFERLEN]; 224 1.1 christos char buff[BUFFERLEN]; 225 1.1 christos fd_set mrd, rd; 226 1.1 christos int maxfd; 227 1.1 christos int inbuf; 228 1.1 christos int n1; 229 1.1 christos int left; 230 1.1 christos 231 1.1 christos FD_ZERO(&mrd); 232 1.1 christos FD_SET(lfd, &mrd); 233 1.1 christos FD_SET(nfd, &mrd); 234 1.1 christos maxfd = nfd; 235 1.1 christos if (lfd > maxfd) 236 1.1 christos maxfd = lfd; 237 1.1 christos debug(2, "nfd %d lfd %d maxfd %d\n", nfd, lfd, maxfd); 238 1.1 christos 239 1.1 christos inbuf = 0; 240 1.1 christos /* 241 1.1 christos * A threaded approach to this loop would have one thread 242 1.1 christos * work on reading lfd (only) all the time and another thread 243 1.1 christos * working on reading nfd all the time. 244 1.1 christos */ 245 1.1 christos while (!terminate) { 246 1.1 christos int n; 247 1.1 christos 248 1.1 christos rd = mrd; 249 1.1 christos 250 1.1 christos n = select(maxfd + 1, &rd, NULL, NULL, NULL); 251 1.1 christos if (n < 0) { 252 1.1 christos switch (errno) 253 1.1 christos { 254 1.1 christos case EINTR : 255 1.1 christos continue; 256 1.1 christos default : 257 1.1 christos syslog(LOG_ERR, "select error: %m"); 258 1.1 christos debug(1, "select error: %s\n", STRERROR(errno)); 259 1.1 christos return; 260 1.1 christos } 261 1.1 christos } 262 1.1 christos 263 1.1 christos if (FD_ISSET(lfd, &rd)) { 264 1.1 christos n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf); 265 1.1 christos 266 1.1 christos debug(3, "read(K):%d\n", n1); 267 1.1 christos 268 1.1 christos if (n1 <= 0) { 269 1.1 christos syslog(LOG_ERR, "read error (k-header): %m"); 270 1.1 christos debug(1, "read error (k-header): %s\n", 271 1.1 christos STRERROR(errno)); 272 1.1 christos return; 273 1.1 christos } 274 1.1 christos 275 1.1 christos left = 0; 276 1.1 christos 277 1.1 christos switch (do_kbuff(n1, buff, &left)) 278 1.1 christos { 279 1.1 christos case R_IO_ERROR : 280 1.1 christos return; 281 1.1 christos case R_MORE : 282 1.1 christos inbuf += left; 283 1.1 christos break; 284 1.1 christos default : 285 1.1 christos inbuf = 0; 286 1.1 christos break; 287 1.1 christos } 288 1.1 christos } 289 1.1 christos 290 1.1 christos if (FD_ISSET(nfd, &rd)) { 291 1.1 christos n1 = recv(nfd, nbuff, sizeof(nbuff), 0); 292 1.1 christos 293 1.1 christos debug(3, "read(N):%d\n", n1); 294 1.1 christos 295 1.1 christos if (n1 <= 0) { 296 1.1 christos syslog(LOG_ERR, "read error (n-header): %m"); 297 1.1 christos debug(1, "read error (n-header): %s\n", 298 1.1 christos STRERROR(errno)); 299 1.1 christos return; 300 1.1 christos } 301 1.1 christos 302 1.1 christos switch (do_packet(n1, nbuff)) 303 1.1 christos { 304 1.1 christos case R_IO_ERROR : 305 1.1 christos return; 306 1.1 christos default : 307 1.1 christos break; 308 1.1 christos } 309 1.1 christos } 310 1.1 christos } 311 1.1 christos } 312 1.1 christos 313 1.1 christos 314 1.1 christos int 315 1.1 christos buildsocket(nicname, sinp) 316 1.1 christos char *nicname; 317 1.1 christos struct sockaddr_in *sinp; 318 1.1 christos { 319 1.1 christos struct sockaddr_in *reqip; 320 1.1 christos struct ifreq req; 321 1.1 christos char opt; 322 1.1 christos 323 1.1 christos debug(2, "binding to %s:%s\n", nicname, inet_ntoa(sinp->sin_addr)); 324 1.1 christos 325 1.1 christos if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { 326 1.1 christos struct in_addr addr; 327 1.1 christos struct ip_mreq mreq; 328 1.1 christos 329 1.1 christos igmpfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); 330 1.1 christos if (igmpfd == -1) { 331 1.1 christos syslog(LOG_ERR, "socket:%m"); 332 1.1 christos debug(1, "socket:%s\n", STRERROR(errno)); 333 1.1 christos return -1; 334 1.1 christos } 335 1.1 christos 336 1.1 christos bzero((char *)&req, sizeof(req)); 337 1.1 christos strncpy(req.ifr_name, nicname, sizeof(req.ifr_name)); 338 1.1 christos req.ifr_name[sizeof(req.ifr_name) - 1] = '\0'; 339 1.1 christos if (ioctl(igmpfd, SIOCGIFADDR, &req) == -1) { 340 1.1 christos syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m"); 341 1.1 christos debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno)); 342 1.1 christos close(igmpfd); 343 1.1 christos igmpfd = -1; 344 1.1 christos return -1; 345 1.1 christos } 346 1.1 christos reqip = (struct sockaddr_in *)&req.ifr_addr; 347 1.1 christos 348 1.1 christos addr = reqip->sin_addr; 349 1.1 christos if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_IF, 350 1.1 christos (char *)&addr, sizeof(addr)) == -1) { 351 1.1 christos syslog(LOG_ERR, "setsockopt(IP_MULTICAST_IF(%s)):%m", 352 1.1 christos inet_ntoa(addr)); 353 1.1 christos debug(1, "setsockopt(IP_MULTICAST_IF(%s)):%s\n", 354 1.1 christos inet_ntoa(addr), STRERROR(errno)); 355 1.1 christos close(igmpfd); 356 1.1 christos igmpfd = -1; 357 1.1 christos return -1; 358 1.1 christos } 359 1.1 christos 360 1.1 christos opt = 0; 361 1.1 christos if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_LOOP, 362 1.1 christos (char *)&opt, sizeof(opt)) == -1) { 363 1.1 christos syslog(LOG_ERR, "setsockopt(IP_MULTICAST_LOOP=0):%m"); 364 1.1 christos debug(1, "setsockopt(IP_MULTICAST_LOOP=0):%s\n", 365 1.1 christos STRERROR(errno)); 366 1.1 christos close(igmpfd); 367 1.1 christos igmpfd = -1; 368 1.1 christos return -1; 369 1.1 christos } 370 1.1 christos 371 1.1 christos opt = 63; 372 1.1 christos if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_TTL, 373 1.1 christos (char *)&opt, sizeof(opt)) == -1) { 374 1.1 christos syslog(LOG_ERR, "setsockopt(IP_MULTICAST_TTL=%d):%m", 375 1.1 christos opt); 376 1.1 christos debug(1, "setsockopt(IP_MULTICAST_TTL=%d):%s\n", opt, 377 1.1 christos STRERROR(errno)); 378 1.1 christos close(igmpfd); 379 1.1 christos igmpfd = -1; 380 1.1 christos return -1; 381 1.1 christos } 382 1.1 christos 383 1.1 christos mreq.imr_multiaddr.s_addr = sinp->sin_addr.s_addr; 384 1.1 christos mreq.imr_interface.s_addr = reqip->sin_addr.s_addr; 385 1.1 christos 386 1.1 christos if (setsockopt(igmpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 387 1.1 christos (char *)&mreq, sizeof(mreq)) == -1) { 388 1.1 christos char buffer[80]; 389 1.1 christos 390 1.1 christos sprintf(buffer, "%s,", inet_ntoa(sinp->sin_addr)); 391 1.1 christos strcat(buffer, inet_ntoa(reqip->sin_addr)); 392 1.1 christos 393 1.1 christos syslog(LOG_ERR, 394 1.1 christos "setsockpt(IP_ADD_MEMBERSHIP,%s):%m", buffer); 395 1.1 christos debug(1, "setsockpt(IP_ADD_MEMBERSHIP,%s):%s\n", 396 1.1 christos buffer, STRERROR(errno)); 397 1.1 christos close(igmpfd); 398 1.1 christos igmpfd = -1; 399 1.1 christos return -1; 400 1.1 christos } 401 1.1 christos } 402 1.1 christos nfd = socket(AF_INET, SOCK_DGRAM, 0); 403 1.1 christos if (nfd == -1) { 404 1.1 christos syslog(LOG_ERR, "socket:%m"); 405 1.1 christos if (igmpfd != -1) { 406 1.1 christos close(igmpfd); 407 1.1 christos igmpfd = -1; 408 1.1 christos } 409 1.1 christos return -1; 410 1.1 christos } 411 1.1 christos bzero((char *)&req, sizeof(req)); 412 1.1 christos strncpy(req.ifr_name, nicname, sizeof(req.ifr_name)); 413 1.1 christos req.ifr_name[sizeof(req.ifr_name) - 1] = '\0'; 414 1.1 christos if (ioctl(nfd, SIOCGIFADDR, &req) == -1) { 415 1.1 christos syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m"); 416 1.1 christos debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno)); 417 1.1 christos close(igmpfd); 418 1.1 christos igmpfd = -1; 419 1.1 christos return -1; 420 1.1 christos } 421 1.1 christos 422 1.1 christos if (bind(nfd, (struct sockaddr *)&req.ifr_addr, 423 1.1 christos sizeof(req.ifr_addr)) == -1) { 424 1.1 christos syslog(LOG_ERR, "bind:%m"); 425 1.1 christos debug(1, "bind:%s\n", STRERROR(errno)); 426 1.1 christos close(nfd); 427 1.1 christos if (igmpfd != -1) { 428 1.1 christos close(igmpfd); 429 1.1 christos igmpfd = -1; 430 1.1 christos } 431 1.1 christos nfd = -1; 432 1.1 christos return -1; 433 1.1 christos } 434 1.1 christos 435 1.1 christos if (connect(nfd, (struct sockaddr *)sinp, sizeof(*sinp)) == -1) { 436 1.1 christos syslog(LOG_ERR, "connect:%m"); 437 1.1 christos debug(1, "connect:%s\n", STRERROR(errno)); 438 1.1 christos close(nfd); 439 1.1 christos if (igmpfd != -1) { 440 1.1 christos close(igmpfd); 441 1.1 christos igmpfd = -1; 442 1.1 christos } 443 1.1 christos nfd = -1; 444 1.1 christos return -1; 445 1.1 christos } 446 1.1 christos syslog(LOG_INFO, "Sending data to %s", inet_ntoa(sinp->sin_addr)); 447 1.1 christos debug(3, "Sending data to %s\n", inet_ntoa(sinp->sin_addr)); 448 1.1 christos 449 1.1 christos return nfd; 450 1.1 christos } 451 1.1 christos 452 1.1 christos 453 1.1 christos int 454 1.1 christos do_packet(pklen, buff) 455 1.1 christos int pklen; 456 1.1 christos char *buff; 457 1.1 christos { 458 1.1 christos synchdr_t *sh; 459 1.1 christos u_32_t magic; 460 1.1 christos int len; 461 1.1 christos int n2; 462 1.1 christos int n3; 463 1.1 christos 464 1.1 christos while (pklen > 0) { 465 1.1 christos if (pklen < sizeof(*sh)) { 466 1.1 christos syslog(LOG_ERR, "packet length too short:%d", pklen); 467 1.1 christos debug(2, "packet length too short:%d\n", pklen); 468 1.1 christos return R_SKIP; 469 1.1 christos } 470 1.1 christos 471 1.1 christos sh = (synchdr_t *)buff; 472 1.1 christos len = ntohl(sh->sm_len); 473 1.1 christos magic = ntohl(sh->sm_magic); 474 1.1 christos 475 1.1 christos if (magic != SYNHDRMAGIC) { 476 1.1 christos syslog(LOG_ERR, "invalid header magic %x", magic); 477 1.1 christos debug(2, "invalid header magic %x\n", magic); 478 1.1 christos return R_SKIP; 479 1.1 christos } 480 1.1 christos 481 1.1 christos if (pklen < len + sizeof(*sh)) { 482 1.1 christos syslog(LOG_ERR, "packet length too short:%d", pklen); 483 1.1 christos debug(2, "packet length too short:%d\n", pklen); 484 1.1 christos return R_SKIP; 485 1.1 christos } 486 1.1 christos 487 1.1 christos if (debuglevel > 3) { 488 1.1 christos printsynchdr(sh); 489 1.1 christos printcommand(sh->sm_cmd); 490 1.1 christos printtable(sh->sm_table); 491 1.1 christos printsmcproto(buff); 492 1.1 christos } 493 1.1 christos 494 1.1 christos n2 = sizeof(*sh) + len; 495 1.1 christos 496 1.1 christos do { 497 1.1 christos n3 = write(lfd, buff, n2); 498 1.1 christos if (n3 <= 0) { 499 1.1 christos syslog(LOG_ERR, "write error: %m"); 500 1.1 christos debug(1, "write error: %s\n", STRERROR(errno)); 501 1.1 christos return R_IO_ERROR; 502 1.1 christos } 503 1.1 christos 504 1.1 christos n2 -= n3; 505 1.1 christos buff += n3; 506 1.1 christos pklen -= n3; 507 1.1 christos } while (n3 != 0); 508 1.1 christos } 509 1.1 christos 510 1.1 christos return R_OKAY; 511 1.1 christos } 512 1.1 christos 513 1.1 christos 514 1.1 christos 515 1.1 christos int 516 1.1 christos do_kbuff(inbuf, buf, left) 517 1.1 christos int inbuf, *left; 518 1.1 christos char *buf; 519 1.1 christos { 520 1.1 christos synchdr_t *sh; 521 1.1 christos u_32_t magic; 522 1.1 christos int complete; 523 1.1 christos int sendlen; 524 1.1 christos int error; 525 1.1 christos int bytes; 526 1.1 christos int len; 527 1.1 christos int n2; 528 1.1 christos int n3; 529 1.1 christos 530 1.1 christos sendlen = 0; 531 1.1 christos bytes = inbuf; 532 1.1 christos error = R_OKAY; 533 1.1 christos sh = (synchdr_t *)buf; 534 1.1 christos 535 1.1 christos for (complete = 0; bytes > 0; complete++) { 536 1.1 christos len = ntohl(sh->sm_len); 537 1.1 christos magic = ntohl(sh->sm_magic); 538 1.1 christos 539 1.1 christos if (magic != SYNHDRMAGIC) { 540 1.1 christos syslog(LOG_ERR, 541 1.1 christos "read invalid header magic 0x%x, flushing", 542 1.1 christos magic); 543 1.1 christos debug(2, "read invalid header magic 0x%x, flushing\n", 544 1.1 christos magic); 545 1.1 christos n2 = SMC_RLOG; 546 1.1 christos (void) ioctl(lfd, SIOCIPFFL, &n2); 547 1.1 christos break; 548 1.1 christos } 549 1.1 christos 550 1.1 christos if (debuglevel > 3) { 551 1.1 christos printsynchdr(sh); 552 1.1 christos printcommand(sh->sm_cmd); 553 1.1 christos printtable(sh->sm_table); 554 1.1 christos putchar('\n'); 555 1.1 christos } 556 1.1 christos 557 1.1 christos if (bytes < sizeof(*sh) + len) { 558 1.1 christos debug(3, "Not enough bytes %d < %d\n", bytes, 559 1.1 christos sizeof(*sh) + len); 560 1.1 christos error = R_MORE; 561 1.1 christos break; 562 1.1 christos } 563 1.1 christos 564 1.1 christos if (debuglevel > 3) { 565 1.1 christos printsmcproto(buf); 566 1.1 christos } 567 1.1 christos 568 1.1 christos sendlen += len + sizeof(*sh); 569 1.1 christos sh = (synchdr_t *)(buf + sendlen); 570 1.1 christos bytes -= sendlen; 571 1.1 christos } 572 1.1 christos 573 1.1 christos if (complete) { 574 1.1 christos n3 = send(nfd, buf, sendlen, 0); 575 1.1 christos if (n3 <= 0) { 576 1.1 christos syslog(LOG_ERR, "write error: %m"); 577 1.1 christos debug(1, "write error: %s\n", STRERROR(errno)); 578 1.1 christos return R_IO_ERROR; 579 1.1 christos } 580 1.1 christos debug(3, "send on %d len %d = %d\n", nfd, sendlen, n3); 581 1.1 christos error = R_OKAY; 582 1.1 christos } 583 1.1 christos 584 1.1 christos /* move buffer to the front,we might need to make 585 1.1 christos * this more efficient, by using a rolling pointer 586 1.1 christos * over the buffer and only copying it, when 587 1.1 christos * we are reaching the end 588 1.1 christos */ 589 1.1 christos if (bytes > 0) { 590 1.1 christos bcopy(buf + bytes, buf, bytes); 591 1.1 christos error = R_MORE; 592 1.1 christos } 593 1.1 christos debug(4, "complete %d bytes %d error %d\n", complete, bytes, error); 594 1.1 christos 595 1.1 christos *left = bytes; 596 1.1 christos 597 1.1 christos return error; 598 1.1 christos } 599 1.1 christos 600 1.1 christos 601 1.1 christos void 602 1.1 christos printcommand(cmd) 603 1.1 christos int cmd; 604 1.1 christos { 605 1.1 christos 606 1.1 christos switch (cmd) 607 1.1 christos { 608 1.1 christos case SMC_CREATE : 609 1.1 christos printf(" cmd:CREATE"); 610 1.1 christos break; 611 1.1 christos case SMC_UPDATE : 612 1.1 christos printf(" cmd:UPDATE"); 613 1.1 christos break; 614 1.1 christos default : 615 1.1 christos printf(" cmd:Unknown(%d)", cmd); 616 1.1 christos break; 617 1.1 christos } 618 1.1 christos } 619 1.1 christos 620 1.1 christos 621 1.1 christos void 622 1.1 christos printtable(table) 623 1.1 christos int table; 624 1.1 christos { 625 1.1 christos switch (table) 626 1.1 christos { 627 1.1 christos case SMC_NAT : 628 1.1 christos printf(" table:NAT"); 629 1.1 christos break; 630 1.1 christos case SMC_STATE : 631 1.1 christos printf(" table:STATE"); 632 1.1 christos break; 633 1.1 christos default : 634 1.1 christos printf(" table:Unknown(%d)", table); 635 1.1 christos break; 636 1.1 christos } 637 1.1 christos } 638 1.1 christos 639 1.1 christos 640 1.1 christos void 641 1.1 christos printsmcproto(buff) 642 1.1 christos char *buff; 643 1.1 christos { 644 1.1 christos syncupdent_t *su; 645 1.1 christos synchdr_t *sh; 646 1.1 christos 647 1.1 christos sh = (synchdr_t *)buff; 648 1.1 christos 649 1.1 christos if (sh->sm_cmd == SMC_CREATE) { 650 1.1 christos ; 651 1.1 christos 652 1.1 christos } else if (sh->sm_cmd == SMC_UPDATE) { 653 1.1 christos su = (syncupdent_t *)buff; 654 1.1 christos if (sh->sm_p == IPPROTO_TCP) { 655 1.1 christos printf(" TCP Update: age %lu state %d/%d\n", 656 1.1 christos su->sup_tcp.stu_age, 657 1.1 christos su->sup_tcp.stu_state[0], 658 1.1 christos su->sup_tcp.stu_state[1]); 659 1.1 christos } 660 1.1 christos } else { 661 1.1 christos printf("Unknown command\n"); 662 1.1 christos } 663 1.1 christos } 664 1.1 christos 665 1.1 christos 666 1.1 christos void 667 1.1 christos printsynchdr(sh) 668 1.1 christos synchdr_t *sh; 669 1.1 christos { 670 1.1 christos 671 1.1 christos printf("v:%d p:%d num:%d len:%d magic:%x", sh->sm_v, sh->sm_p, 672 1.1 christos ntohl(sh->sm_num), ntohl(sh->sm_len), ntohl(sh->sm_magic)); 673 1.1 christos } 674