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 13 #include <ctype.h> 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 n = 0; 144 timeout = ps->snf_timeout; 145 while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { 146 /* 147 * Has "pcap_breakloop()" been called? 148 */ 149 if (p->break_loop) { 150 if (n == 0) { 151 p->break_loop = 0; 152 return (-2); 153 } else { 154 return (n); 155 } 156 } 157 158 err = snf_ring_recv(ps->snf_ring, timeout, &req); 159 160 if (err) { 161 if (err == EBUSY || err == EAGAIN) { 162 return (n); 163 } 164 else if (err == EINTR) { 165 timeout = 0; 166 continue; 167 } 168 else { 169 pcap_fmt_errmsg_for_errno(p->errbuf, 170 PCAP_ERRBUF_SIZE, err, "snf_read"); 171 return -1; 172 } 173 } 174 175 caplen = req.length; 176 if (caplen > p->snapshot) 177 caplen = p->snapshot; 178 179 if ((p->fcode.bf_insns == NULL) || 180 bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 181 hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); 182 hdr.caplen = caplen; 183 hdr.len = req.length; 184 callback(user, &hdr, req.pkt_addr); 185 } 186 n++; 187 188 /* After one successful packet is received, we won't block 189 * again for that timeout. */ 190 if (timeout != 0) 191 timeout = 0; 192 } 193 return (n); 194 } 195 196 static int 197 snf_setfilter(pcap_t *p, struct bpf_program *fp) 198 { 199 if (!p) 200 return -1; 201 if (!fp) { 202 strncpy(p->errbuf, "setfilter: No filter specified", 203 sizeof(p->errbuf)); 204 return -1; 205 } 206 207 /* Make our private copy of the filter */ 208 209 if (install_bpf_program(p, fp) < 0) 210 return -1; 211 212 return (0); 213 } 214 215 static int 216 snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 217 { 218 #ifdef SNF_HAVE_INJECT_API 219 struct pcap_snf *ps = p->priv; 220 int rc; 221 if (ps->snf_inj == NULL) { 222 rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); 223 if (rc) { 224 pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 225 rc, "snf_inject_open"); 226 return (-1); 227 } 228 } 229 230 rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); 231 if (!rc) { 232 return (size); 233 } 234 else { 235 pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 236 rc, "snf_inject_send"); 237 return (-1); 238 } 239 #else 240 strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", 241 PCAP_ERRBUF_SIZE); 242 return (-1); 243 #endif 244 } 245 246 static int 247 snf_activate(pcap_t* p) 248 { 249 struct pcap_snf *ps = p->priv; 250 char *device = p->opt.device; 251 const char *nr = NULL; 252 int err; 253 int flags = -1, ring_id = -1; 254 255 if (device == NULL) { 256 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); 257 return -1; 258 } 259 260 /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. 261 * Since libpcap isn't thread-safe */ 262 if ((nr = getenv("SNF_FLAGS")) && *nr) 263 flags = strtol(nr, NULL, 0); 264 else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) 265 flags = SNF_F_PSHARED; 266 else 267 nr = NULL; 268 269 270 /* Allow pcap_set_buffer_size() to set dataring_size. 271 * Default is zero which allows setting from env SNF_DATARING_SIZE. 272 * pcap_set_buffer_size() is in bytes while snf_open() accepts values 273 * between 0 and 1048576 in Megabytes. Values in this range are 274 * mapped to 1MB. 275 */ 276 err = snf_open(ps->snf_boardnum, 277 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 278 NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 279 (p->opt.buffer_size > 0 && p->opt.buffer_size < 1048576) ? 1048576 : p->opt.buffer_size, /* default to SNF_DATARING_SIZE from env */ 280 flags, /* may want pshared */ 281 &ps->snf_handle); 282 if (err != 0) { 283 pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 284 err, "snf_open failed"); 285 return -1; 286 } 287 288 if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { 289 ring_id = (int) strtol(nr, NULL, 0); 290 } 291 err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); 292 if (err != 0) { 293 pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 294 err, "snf_ring_open_id(ring=%d) failed", ring_id); 295 return -1; 296 } 297 298 /* 299 * Turn a negative snapshot value (invalid), a snapshot value of 300 * 0 (unspecified), or a value bigger than the normal maximum 301 * value, into the maximum allowed value. 302 * 303 * If some application really *needs* a bigger snapshot 304 * length, we should just increase MAXIMUM_SNAPLEN. 305 */ 306 if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 307 p->snapshot = MAXIMUM_SNAPLEN; 308 309 if (p->opt.timeout <= 0) 310 ps->snf_timeout = -1; 311 else 312 ps->snf_timeout = p->opt.timeout; 313 314 err = snf_start(ps->snf_handle); 315 if (err != 0) { 316 pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 317 err, "snf_start failed"); 318 return -1; 319 } 320 321 /* 322 * "select()" and "poll()" don't work on snf descriptors. 323 */ 324 #ifndef _WIN32 325 p->selectable_fd = -1; 326 #endif /* !_WIN32 */ 327 p->linktype = DLT_EN10MB; 328 p->read_op = snf_read; 329 p->inject_op = snf_inject; 330 p->setfilter_op = snf_setfilter; 331 p->setdirection_op = NULL; /* Not implemented.*/ 332 p->set_datalink_op = snf_set_datalink; 333 p->getnonblock_op = snf_getnonblock; 334 p->setnonblock_op = snf_setnonblock; 335 p->stats_op = snf_pcap_stats; 336 p->cleanup_op = snf_platform_cleanup; 337 #ifdef SNF_HAVE_INJECT_API 338 ps->snf_inj = NULL; 339 #endif 340 return 0; 341 } 342 343 #define MAX_DESC_LENGTH 128 344 int 345 snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf) 346 { 347 pcap_if_t *dev; 348 #ifdef _WIN32 349 struct sockaddr_in addr; 350 #endif 351 struct snf_ifaddrs *ifaddrs, *ifa; 352 char name[MAX_DESC_LENGTH]; 353 char desc[MAX_DESC_LENGTH]; 354 int ret, allports = 0, merge = 0; 355 const char *nr = NULL; 356 357 if (snf_init(SNF_VERSION_API)) { 358 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 359 "snf_getifaddrs: snf_init failed"); 360 return (-1); 361 } 362 363 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) 364 { 365 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 366 errno, "snf_getifaddrs"); 367 return (-1); 368 } 369 if ((nr = getenv("SNF_FLAGS")) && *nr) { 370 errno = 0; 371 merge = strtol(nr, NULL, 0); 372 if (errno) { 373 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 374 "snf_getifaddrs: SNF_FLAGS is not a valid number"); 375 return (-1); 376 } 377 merge = merge & SNF_F_AGGREGATE_PORTMASK; 378 } 379 380 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->snf_ifa_next) { 381 /* 382 * Myricom SNF adapter ports may appear as regular 383 * network interfaces, which would already have been 384 * added to the list of adapters by pcap_platform_finddevs() 385 * if this isn't an SNF-only version of libpcap. 386 * 387 * Our create routine intercepts pcap_create() calls for 388 * those interfaces and arranges that they will be 389 * opened using the SNF API instead. 390 * 391 * So if we already have an entry for the device, we 392 * don't add an additional entry for it, we just 393 * update the description for it, if any, to indicate 394 * which snfN device it is. Otherwise, we add an entry 395 * for it. 396 * 397 * In either case, if SNF_F_AGGREGATE_PORTMASK is set 398 * in SNF_FLAGS, we add this port to the bitmask 399 * of ports, which we use to generate a device 400 * we can use to capture on all ports. 401 * 402 * Generate the description string. If port aggregation 403 * is set, use 2^{port number} as the unit number, 404 * rather than {port number}. 405 * 406 * XXX - do entries in this list have IP addresses for 407 * the port? If so, should we add them to the 408 * entry for the device, if they're not already in the 409 * list of IP addresses for the device? 410 */ 411 (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d", 412 merge ? "Merge Bitmask Port " : "", 413 merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum); 414 /* 415 * Add the port to the bitmask. 416 */ 417 if (merge) 418 allports |= 1 << ifa->snf_ifa_portnum; 419 /* 420 * See if there's already an entry for the device 421 * with the name ifa->snf_ifa_name. 422 */ 423 dev = find_dev(devlistp, ifa->snf_ifa_name); 424 if (dev != NULL) { 425 /* 426 * Yes. Update its description. 427 */ 428 char *desc_str; 429 430 desc_str = strdup(desc); 431 if (desc_str == NULL) { 432 pcap_fmt_errmsg_for_errno(errbuf, 433 PCAP_ERRBUF_SIZE, errno, 434 "snf_findalldevs strdup"); 435 return -1; 436 } 437 free(dev->description); 438 dev->description = desc_str; 439 } else { 440 /* 441 * No. Add an entry for it. 442 * 443 * XXX - is there a notion of "up" or "running", 444 * and can we determine whether something's 445 * plugged into the adapter and set 446 * PCAP_IF_CONNECTION_STATUS_CONNECTED or 447 * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? 448 */ 449 dev = add_dev(devlistp, ifa->snf_ifa_name, 0, desc, 450 errbuf); 451 if (dev == NULL) 452 return -1; 453 #ifdef _WIN32 454 /* 455 * On Windows, fill in IP# from device name 456 */ 457 ret = inet_pton(AF_INET, dev->name, &addr.sin_addr); 458 if (ret == 1) { 459 /* 460 * Successful conversion of device name 461 * to IPv4 address. 462 */ 463 addr.sin_family = AF_INET; 464 if (add_addr_to_dev(dev, &addr, sizeof(addr), 465 NULL, 0, NULL, 0, NULL, 0, errbuf) == -1) 466 return -1; 467 } else if (ret == -1) { 468 /* 469 * Error. 470 */ 471 pcap_fmt_errmsg_for_errno(errbuf, 472 PCAP_ERRBUF_SIZE, errno, 473 "sinf_findalldevs inet_pton"); 474 return -1; 475 } 476 #endif _WIN32 477 } 478 } 479 snf_freeifaddrs(ifaddrs); 480 /* 481 * Create a snfX entry if port aggregation is enabled 482 */ 483 if (merge) { 484 /* 485 * Add a new entry with all ports bitmask 486 */ 487 (void)pcap_snprintf(name,MAX_DESC_LENGTH,"snf%d",allports); 488 (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d", 489 allports); 490 /* 491 * XXX - is there any notion of "up" and "running" that 492 * would apply to this device, given that it handles 493 * multiple ports? 494 * 495 * Presumably, there's no notion of "connected" vs. 496 * "disconnected", as "is this plugged into a network?" 497 * would be a per-port property. 498 */ 499 if (add_dev(devlistp, name, 500 PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc, 501 errbuf) == NULL) 502 return (-1); 503 /* 504 * XXX - should we give it a list of addresses with all 505 * the addresses for all the ports? 506 */ 507 } 508 509 return 0; 510 } 511 512 pcap_t * 513 snf_create(const char *device, char *ebuf, int *is_ours) 514 { 515 pcap_t *p; 516 int boardnum = -1; 517 struct snf_ifaddrs *ifaddrs, *ifa; 518 size_t devlen; 519 struct pcap_snf *ps; 520 521 if (snf_init(SNF_VERSION_API)) { 522 /* Can't initialize the API, so no SNF devices */ 523 *is_ours = 0; 524 return NULL; 525 } 526 527 /* 528 * Match a given interface name to our list of interface names, from 529 * which we can obtain the intended board number 530 */ 531 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { 532 /* Can't get SNF addresses */ 533 *is_ours = 0; 534 return NULL; 535 } 536 devlen = strlen(device) + 1; 537 ifa = ifaddrs; 538 while (ifa) { 539 if (strncmp(device, ifa->snf_ifa_name, devlen) == 0) { 540 boardnum = ifa->snf_ifa_boardnum; 541 break; 542 } 543 ifa = ifa->snf_ifa_next; 544 } 545 snf_freeifaddrs(ifaddrs); 546 547 if (ifa == NULL) { 548 /* 549 * If we can't find the device by name, support the name "snfX" 550 * and "snf10gX" where X is the board number. 551 */ 552 if (sscanf(device, "snf10g%d", &boardnum) != 1 && 553 sscanf(device, "snf%d", &boardnum) != 1) { 554 /* Nope, not a supported name */ 555 *is_ours = 0; 556 return NULL; 557 } 558 } 559 560 /* OK, it's probably ours. */ 561 *is_ours = 1; 562 563 p = pcap_create_common(ebuf, sizeof (struct pcap_snf)); 564 if (p == NULL) 565 return NULL; 566 ps = p->priv; 567 568 /* 569 * We support microsecond and nanosecond time stamps. 570 */ 571 p->tstamp_precision_count = 2; 572 p->tstamp_precision_list = malloc(2 * sizeof(u_int)); 573 if (p->tstamp_precision_list == NULL) { 574 pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, 575 "malloc"); 576 pcap_close(p); 577 return NULL; 578 } 579 p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; 580 p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; 581 582 p->activate_op = snf_activate; 583 ps->snf_boardnum = boardnum; 584 return p; 585 } 586 587 #ifdef SNF_ONLY 588 /* 589 * This libpcap build supports only SNF cards, not regular network 590 * interfaces.. 591 */ 592 593 /* 594 * There are no regular interfaces, just SNF interfaces. 595 */ 596 int 597 pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 598 { 599 return (0); 600 } 601 602 /* 603 * Attempts to open a regular interface fail. 604 */ 605 pcap_t * 606 pcap_create_interface(const char *device, char *errbuf) 607 { 608 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 609 "This version of libpcap only supports SNF cards"); 610 return NULL; 611 } 612 613 /* 614 * Libpcap version string. 615 */ 616 const char * 617 pcap_lib_version(void) 618 { 619 return (PCAP_VERSION_STRING " (SNF-only)"); 620 } 621 #endif 622