1 #include <config.h> 2 3 #ifndef _WIN32 4 #include <sys/param.h> 5 #endif /* !_WIN32 */ 6 7 #include <stdlib.h> 8 #include <string.h> 9 #include <errno.h> 10 #include <limits.h> /* for INT_MAX */ 11 12 #ifndef _WIN32 13 #include <netinet/in.h> 14 #include <sys/mman.h> 15 #include <sys/socket.h> 16 #include <sys/types.h> 17 #include <unistd.h> 18 #endif /* !_WIN32 */ 19 20 #include <snf.h> 21 #if SNF_VERSION_API >= 0x0003 22 #define SNF_HAVE_INJECT_API 23 #endif 24 25 #include "pcap-int.h" 26 #include "pcap-snf.h" 27 28 /* 29 * Private data for capturing on SNF devices. 30 */ 31 struct pcap_snf { 32 snf_handle_t snf_handle; /* opaque device handle */ 33 snf_ring_t snf_ring; /* opaque device ring handle */ 34 #ifdef SNF_HAVE_INJECT_API 35 snf_inject_t snf_inj; /* inject handle, if inject is used */ 36 #endif 37 int snf_timeout; 38 int snf_boardnum; 39 }; 40 41 static int 42 snf_set_datalink(pcap_t *p, int dlt) 43 { 44 p->linktype = dlt; 45 return (0); 46 } 47 48 static int 49 snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) 50 { 51 struct snf_ring_stats stats; 52 struct pcap_snf *snfps = p->priv; 53 int rc; 54 55 if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { 56 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 57 rc, "snf_get_stats"); 58 return -1; 59 } 60 ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; 61 ps->ps_drop = stats.ring_pkt_overflow; 62 ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; 63 return 0; 64 } 65 66 static void 67 snf_platform_cleanup(pcap_t *p) 68 { 69 struct pcap_snf *ps = p->priv; 70 71 #ifdef SNF_HAVE_INJECT_API 72 if (ps->snf_inj) 73 snf_inject_close(ps->snf_inj); 74 #endif 75 snf_ring_close(ps->snf_ring); 76 snf_close(ps->snf_handle); 77 pcapint_cleanup_live_common(p); 78 } 79 80 static int 81 snf_getnonblock(pcap_t *p) 82 { 83 struct pcap_snf *ps = p->priv; 84 85 return (ps->snf_timeout == 0); 86 } 87 88 static int 89 snf_setnonblock(pcap_t *p, int nonblock) 90 { 91 struct pcap_snf *ps = p->priv; 92 93 if (nonblock) 94 ps->snf_timeout = 0; 95 else { 96 if (p->opt.timeout <= 0) 97 ps->snf_timeout = -1; /* forever */ 98 else 99 ps->snf_timeout = p->opt.timeout; 100 } 101 return (0); 102 } 103 104 #define _NSEC_PER_SEC 1000000000 105 106 static inline 107 struct timeval 108 snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) 109 { 110 struct timeval tv; 111 long tv_nsec; 112 const static struct timeval zero_timeval; 113 114 if (ts_nanosec == 0) 115 return zero_timeval; 116 117 tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; 118 tv_nsec = (ts_nanosec % _NSEC_PER_SEC); 119 120 /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ 121 if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) 122 tv.tv_usec = tv_nsec; 123 else 124 tv.tv_usec = tv_nsec / 1000; 125 126 return tv; 127 } 128 129 static int 130 snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 131 { 132 struct pcap_snf *ps = p->priv; 133 struct pcap_pkthdr hdr; 134 int i, flags, err, caplen, n; 135 struct snf_recv_req req; 136 int nonblock, timeout; 137 138 if (!p) 139 return -1; 140 141 /* 142 * This can conceivably process more than INT_MAX packets, 143 * which would overflow the packet count, causing it either 144 * to look like a negative number, and thus cause us to 145 * return a value that looks like an error, or overflow 146 * back into positive territory, and thus cause us to 147 * return a too-low count. 148 * 149 * Therefore, if the packet count is unlimited, we clip 150 * it at INT_MAX; this routine is not expected to 151 * process packets indefinitely, so that's not an issue. 152 */ 153 if (PACKET_COUNT_IS_UNLIMITED(cnt)) 154 cnt = INT_MAX; 155 156 n = 0; 157 timeout = ps->snf_timeout; 158 while (n < cnt) { 159 /* 160 * Has "pcap_breakloop()" been called? 161 */ 162 if (p->break_loop) { 163 if (n == 0) { 164 p->break_loop = 0; 165 return (-2); 166 } else { 167 return (n); 168 } 169 } 170 171 err = snf_ring_recv(ps->snf_ring, timeout, &req); 172 173 if (err) { 174 if (err == EBUSY || err == EAGAIN) { 175 return (n); 176 } 177 else if (err == EINTR) { 178 timeout = 0; 179 continue; 180 } 181 else { 182 pcapint_fmt_errmsg_for_errno(p->errbuf, 183 PCAP_ERRBUF_SIZE, err, "snf_read"); 184 return -1; 185 } 186 } 187 188 caplen = req.length; 189 if (caplen > p->snapshot) 190 caplen = p->snapshot; 191 192 if ((p->fcode.bf_insns == NULL) || 193 pcapint_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 194 hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); 195 hdr.caplen = caplen; 196 hdr.len = req.length; 197 callback(user, &hdr, req.pkt_addr); 198 n++; 199 } 200 201 /* After one successful packet is received, we won't block 202 * again for that timeout. */ 203 if (timeout != 0) 204 timeout = 0; 205 } 206 return (n); 207 } 208 209 static int 210 snf_inject(pcap_t *p, const void *buf _U_, int size _U_) 211 { 212 #ifdef SNF_HAVE_INJECT_API 213 struct pcap_snf *ps = p->priv; 214 int rc; 215 if (ps->snf_inj == NULL) { 216 rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); 217 if (rc) { 218 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 219 rc, "snf_inject_open"); 220 return (-1); 221 } 222 } 223 224 rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); 225 if (!rc) { 226 return (size); 227 } 228 else { 229 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 230 rc, "snf_inject_send"); 231 return (-1); 232 } 233 #else 234 pcapint_strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", 235 PCAP_ERRBUF_SIZE); 236 return (-1); 237 #endif 238 } 239 240 static int 241 snf_activate(pcap_t* p) 242 { 243 struct pcap_snf *ps = p->priv; 244 char *device = p->opt.device; 245 const char *nr = NULL; 246 int err; 247 int flags = -1, ring_id = -1; 248 249 if (device == NULL) { 250 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); 251 return -1; 252 } 253 254 /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. 255 * Since libpcap isn't thread-safe */ 256 if ((nr = getenv("SNF_FLAGS")) && *nr) 257 flags = strtol(nr, NULL, 0); 258 else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) 259 flags = SNF_F_PSHARED; 260 else 261 nr = NULL; 262 263 264 /* Allow pcap_set_buffer_size() to set dataring_size. 265 * Default is zero which allows setting from env SNF_DATARING_SIZE. 266 * pcap_set_buffer_size() is in bytes while snf_open() accepts values 267 * between 0 and 1048576 in Megabytes. Values in this range are 268 * mapped to 1MB. 269 */ 270 err = snf_open(ps->snf_boardnum, 271 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 272 NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 273 (p->opt.buffer_size > 0 && p->opt.buffer_size < 1048576) ? 1048576 : p->opt.buffer_size, /* default to SNF_DATARING_SIZE from env */ 274 flags, /* may want pshared */ 275 &ps->snf_handle); 276 if (err != 0) { 277 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 278 err, "snf_open failed"); 279 return -1; 280 } 281 282 if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { 283 ring_id = (int) strtol(nr, NULL, 0); 284 } 285 err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); 286 if (err != 0) { 287 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 288 err, "snf_ring_open_id(ring=%d) failed", ring_id); 289 return -1; 290 } 291 292 /* 293 * Turn a negative snapshot value (invalid), a snapshot value of 294 * 0 (unspecified), or a value bigger than the normal maximum 295 * value, into the maximum allowed value. 296 * 297 * If some application really *needs* a bigger snapshot 298 * length, we should just increase MAXIMUM_SNAPLEN. 299 */ 300 if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 301 p->snapshot = MAXIMUM_SNAPLEN; 302 303 if (p->opt.timeout <= 0) 304 ps->snf_timeout = -1; 305 else 306 ps->snf_timeout = p->opt.timeout; 307 308 err = snf_start(ps->snf_handle); 309 if (err != 0) { 310 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 311 err, "snf_start failed"); 312 return -1; 313 } 314 315 /* 316 * "select()" and "poll()" don't work on snf descriptors. 317 */ 318 #ifndef _WIN32 319 p->selectable_fd = -1; 320 #endif /* !_WIN32 */ 321 p->linktype = DLT_EN10MB; 322 p->read_op = snf_read; 323 p->inject_op = snf_inject; 324 p->setfilter_op = pcapint_install_bpf_program; 325 p->setdirection_op = NULL; /* Not implemented.*/ 326 p->set_datalink_op = snf_set_datalink; 327 p->getnonblock_op = snf_getnonblock; 328 p->setnonblock_op = snf_setnonblock; 329 p->stats_op = snf_pcap_stats; 330 p->cleanup_op = snf_platform_cleanup; 331 #ifdef SNF_HAVE_INJECT_API 332 ps->snf_inj = NULL; 333 #endif 334 return 0; 335 } 336 337 #define MAX_DESC_LENGTH 128 338 int 339 snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf) 340 { 341 pcap_if_t *dev; 342 #ifdef _WIN32 343 struct sockaddr_in addr; 344 #endif 345 struct snf_ifaddrs *ifaddrs, *ifa; 346 char name[MAX_DESC_LENGTH]; 347 char desc[MAX_DESC_LENGTH]; 348 int ret, allports = 0, merge = 0; 349 const char *nr = NULL; 350 351 if (snf_init(SNF_VERSION_API)) { 352 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 353 "snf_getifaddrs: snf_init failed"); 354 return (-1); 355 } 356 357 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) 358 { 359 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 360 errno, "snf_getifaddrs"); 361 return (-1); 362 } 363 if ((nr = getenv("SNF_FLAGS")) && *nr) { 364 errno = 0; 365 merge = strtol(nr, NULL, 0); 366 if (errno) { 367 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 368 "snf_getifaddrs: SNF_FLAGS is not a valid number"); 369 return (-1); 370 } 371 merge = merge & SNF_F_AGGREGATE_PORTMASK; 372 } 373 374 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->snf_ifa_next) { 375 /* 376 * Myricom SNF adapter ports may appear as regular 377 * network interfaces, which would already have been 378 * added to the list of adapters by pcapint_platform_finddevs() 379 * if this isn't an SNF-only version of libpcap. 380 * 381 * Our create routine intercepts pcap_create() calls for 382 * those interfaces and arranges that they will be 383 * opened using the SNF API instead. 384 * 385 * So if we already have an entry for the device, we 386 * don't add an additional entry for it, we just 387 * update the description for it, if any, to indicate 388 * which snfN device it is. Otherwise, we add an entry 389 * for it. 390 * 391 * In either case, if SNF_F_AGGREGATE_PORTMASK is set 392 * in SNF_FLAGS, we add this port to the bitmask 393 * of ports, which we use to generate a device 394 * we can use to capture on all ports. 395 * 396 * Generate the description string. If port aggregation 397 * is set, use 2^{port number} as the unit number, 398 * rather than {port number}. 399 * 400 * XXX - do entries in this list have IP addresses for 401 * the port? If so, should we add them to the 402 * entry for the device, if they're not already in the 403 * list of IP addresses for the device? 404 */ 405 (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d", 406 merge ? "Merge Bitmask Port " : "", 407 merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum); 408 /* 409 * Add the port to the bitmask. 410 */ 411 if (merge) 412 allports |= 1 << ifa->snf_ifa_portnum; 413 /* 414 * See if there's already an entry for the device 415 * with the name ifa->snf_ifa_name. 416 */ 417 dev = pcapint_find_dev(devlistp, ifa->snf_ifa_name); 418 if (dev != NULL) { 419 /* 420 * Yes. Update its description. 421 */ 422 char *desc_str; 423 424 desc_str = strdup(desc); 425 if (desc_str == NULL) { 426 pcapint_fmt_errmsg_for_errno(errbuf, 427 PCAP_ERRBUF_SIZE, errno, 428 "snf_findalldevs strdup"); 429 return -1; 430 } 431 free(dev->description); 432 dev->description = desc_str; 433 } else { 434 /* 435 * No. Add an entry for it. 436 * 437 * XXX - is there a notion of "up" or "running", 438 * and can we determine whether something's 439 * plugged into the adapter and set 440 * PCAP_IF_CONNECTION_STATUS_CONNECTED or 441 * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? 442 */ 443 dev = pcapint_add_dev(devlistp, ifa->snf_ifa_name, 0, desc, 444 errbuf); 445 if (dev == NULL) 446 return -1; 447 #ifdef _WIN32 448 /* 449 * On Windows, fill in IP# from device name 450 */ 451 ret = inet_pton(AF_INET, dev->name, &addr.sin_addr); 452 if (ret == 1) { 453 /* 454 * Successful conversion of device name 455 * to IPv4 address. 456 */ 457 addr.sin_family = AF_INET; 458 if (pcapint_add_addr_to_dev(dev, &addr, sizeof(addr), 459 NULL, 0, NULL, 0, NULL, 0, errbuf) == -1) 460 return -1; 461 } else if (ret == -1) { 462 /* 463 * Error. 464 */ 465 pcapint_fmt_errmsg_for_errno(errbuf, 466 PCAP_ERRBUF_SIZE, errno, 467 "sinf_findalldevs inet_pton"); 468 return -1; 469 } 470 #endif _WIN32 471 } 472 } 473 snf_freeifaddrs(ifaddrs); 474 /* 475 * Create a snfX entry if port aggregation is enabled 476 */ 477 if (merge) { 478 /* 479 * Add a new entry with all ports bitmask 480 */ 481 (void)snprintf(name,MAX_DESC_LENGTH,"snf%d",allports); 482 (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d", 483 allports); 484 /* 485 * XXX - is there any notion of "up" and "running" that 486 * would apply to this device, given that it handles 487 * multiple ports? 488 * 489 * Presumably, there's no notion of "connected" vs. 490 * "disconnected", as "is this plugged into a network?" 491 * would be a per-port property. 492 */ 493 if (pcapint_add_dev(devlistp, name, 494 PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc, 495 errbuf) == NULL) 496 return (-1); 497 /* 498 * XXX - should we give it a list of addresses with all 499 * the addresses for all the ports? 500 */ 501 } 502 503 return 0; 504 } 505 506 pcap_t * 507 snf_create(const char *device, char *ebuf, int *is_ours) 508 { 509 pcap_t *p; 510 int boardnum = -1; 511 struct snf_ifaddrs *ifaddrs, *ifa; 512 size_t devlen; 513 struct pcap_snf *ps; 514 515 if (snf_init(SNF_VERSION_API)) { 516 /* Can't initialize the API, so no SNF devices */ 517 *is_ours = 0; 518 return NULL; 519 } 520 521 /* 522 * Match a given interface name to our list of interface names, from 523 * which we can obtain the intended board number 524 */ 525 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { 526 /* Can't get SNF addresses */ 527 *is_ours = 0; 528 return NULL; 529 } 530 devlen = strlen(device) + 1; 531 ifa = ifaddrs; 532 while (ifa) { 533 if (strncmp(device, ifa->snf_ifa_name, devlen) == 0) { 534 boardnum = ifa->snf_ifa_boardnum; 535 break; 536 } 537 ifa = ifa->snf_ifa_next; 538 } 539 snf_freeifaddrs(ifaddrs); 540 541 if (ifa == NULL) { 542 /* 543 * If we can't find the device by name, support the name "snfX" 544 * and "snf10gX" where X is the board number. 545 */ 546 if (sscanf(device, "snf10g%d", &boardnum) != 1 && 547 sscanf(device, "snf%d", &boardnum) != 1) { 548 /* Nope, not a supported name */ 549 *is_ours = 0; 550 return NULL; 551 } 552 } 553 554 /* OK, it's probably ours. */ 555 *is_ours = 1; 556 557 p = PCAP_CREATE_COMMON(ebuf, struct pcap_snf); 558 if (p == NULL) 559 return NULL; 560 ps = p->priv; 561 562 /* 563 * We support microsecond and nanosecond time stamps. 564 */ 565 p->tstamp_precision_list = malloc(2 * sizeof(u_int)); 566 if (p->tstamp_precision_list == NULL) { 567 pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, 568 "malloc"); 569 pcap_close(p); 570 return NULL; 571 } 572 p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; 573 p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; 574 p->tstamp_precision_count = 2; 575 576 p->activate_op = snf_activate; 577 ps->snf_boardnum = boardnum; 578 return p; 579 } 580 581 #ifdef SNF_ONLY 582 /* 583 * This libpcap build supports only SNF cards, not regular network 584 * interfaces.. 585 */ 586 587 /* 588 * There are no regular interfaces, just SNF interfaces. 589 */ 590 int 591 pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 592 { 593 return (0); 594 } 595 596 /* 597 * Attempts to open a regular interface fail. 598 */ 599 pcap_t * 600 pcapint_create_interface(const char *device, char *errbuf) 601 { 602 snprintf(errbuf, PCAP_ERRBUF_SIZE, 603 "This version of libpcap only supports SNF cards"); 604 return NULL; 605 } 606 607 /* 608 * Libpcap version string. 609 */ 610 const char * 611 pcap_lib_version(void) 612 { 613 return (PCAP_VERSION_STRING " (SNF-only)"); 614 } 615 #endif 616