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