1 #ifdef HAVE_CONFIG_H 2 #include "config.h" 3 #endif 4 5 #include <sys/param.h> 6 7 #include <stdlib.h> 8 #include <string.h> 9 #include <errno.h> 10 11 #include <ctype.h> 12 #include <netinet/in.h> 13 #include <sys/mman.h> 14 #include <sys/socket.h> 15 #include <sys/types.h> 16 #include <unistd.h> 17 18 #include <snf.h> 19 #if SNF_VERSION_API >= 0x0003 20 #define SNF_HAVE_INJECT_API 21 #endif 22 23 #include "pcap-int.h" 24 #include "pcap-snf.h" 25 26 /* 27 * Private data for capturing on SNF devices. 28 */ 29 struct pcap_snf { 30 snf_handle_t snf_handle; /* opaque device handle */ 31 snf_ring_t snf_ring; /* opaque device ring handle */ 32 #ifdef SNF_HAVE_INJECT_API 33 snf_inject_t snf_inj; /* inject handle, if inject is used */ 34 #endif 35 int snf_timeout; 36 int snf_boardnum; 37 }; 38 39 static int 40 snf_set_datalink(pcap_t *p, int dlt) 41 { 42 p->linktype = dlt; 43 return (0); 44 } 45 46 static int 47 snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) 48 { 49 struct snf_ring_stats stats; 50 struct pcap_snf *snfps = p->priv; 51 int rc; 52 53 if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { 54 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", 55 pcap_strerror(rc)); 56 return -1; 57 } 58 ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; 59 ps->ps_drop = stats.ring_pkt_overflow; 60 ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; 61 return 0; 62 } 63 64 static void 65 snf_platform_cleanup(pcap_t *p) 66 { 67 struct pcap_snf *ps = p->priv; 68 69 #ifdef SNF_HAVE_INJECT_API 70 if (ps->snf_inj) 71 snf_inject_close(ps->snf_inj); 72 #endif 73 snf_ring_close(ps->snf_ring); 74 snf_close(ps->snf_handle); 75 pcap_cleanup_live_common(p); 76 } 77 78 static int 79 snf_getnonblock(pcap_t *p, char *errbuf) 80 { 81 struct pcap_snf *ps = p->priv; 82 83 return (ps->snf_timeout == 0); 84 } 85 86 static int 87 snf_setnonblock(pcap_t *p, int nonblock, char *errbuf) 88 { 89 struct pcap_snf *ps = p->priv; 90 91 if (nonblock) 92 ps->snf_timeout = 0; 93 else { 94 if (p->opt.timeout <= 0) 95 ps->snf_timeout = -1; /* forever */ 96 else 97 ps->snf_timeout = p->opt.timeout; 98 } 99 return (0); 100 } 101 102 #define _NSEC_PER_SEC 1000000000 103 104 static inline 105 struct timeval 106 snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) 107 { 108 struct timeval tv; 109 long tv_nsec; 110 111 if (ts_nanosec == 0) 112 return (struct timeval) { 0, 0 }; 113 114 tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; 115 tv_nsec = (ts_nanosec % _NSEC_PER_SEC); 116 117 /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ 118 if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) 119 tv.tv_usec = tv_nsec; 120 else 121 tv.tv_usec = tv_nsec / 1000; 122 123 return tv; 124 } 125 126 static int 127 snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 128 { 129 struct pcap_snf *ps = p->priv; 130 struct pcap_pkthdr hdr; 131 int i, flags, err, caplen, n; 132 struct snf_recv_req req; 133 int nonblock, timeout; 134 135 if (!p) 136 return -1; 137 138 n = 0; 139 timeout = ps->snf_timeout; 140 while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { 141 /* 142 * Has "pcap_breakloop()" been called? 143 */ 144 if (p->break_loop) { 145 if (n == 0) { 146 p->break_loop = 0; 147 return (-2); 148 } else { 149 return (n); 150 } 151 } 152 153 err = snf_ring_recv(ps->snf_ring, timeout, &req); 154 155 if (err) { 156 if (err == EBUSY || err == EAGAIN) { 157 return (n); 158 } 159 else if (err == EINTR) { 160 timeout = 0; 161 continue; 162 } 163 else { 164 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", 165 pcap_strerror(err)); 166 return -1; 167 } 168 } 169 170 caplen = req.length; 171 if (caplen > p->snapshot) 172 caplen = p->snapshot; 173 174 if ((p->fcode.bf_insns == NULL) || 175 bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 176 hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); 177 hdr.caplen = caplen; 178 hdr.len = req.length; 179 callback(user, &hdr, req.pkt_addr); 180 } 181 n++; 182 183 /* After one successful packet is received, we won't block 184 * again for that timeout. */ 185 if (timeout != 0) 186 timeout = 0; 187 } 188 return (n); 189 } 190 191 static int 192 snf_setfilter(pcap_t *p, struct bpf_program *fp) 193 { 194 if (!p) 195 return -1; 196 if (!fp) { 197 strncpy(p->errbuf, "setfilter: No filter specified", 198 sizeof(p->errbuf)); 199 return -1; 200 } 201 202 /* Make our private copy of the filter */ 203 204 if (install_bpf_program(p, fp) < 0) 205 return -1; 206 207 return (0); 208 } 209 210 static int 211 snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 212 { 213 #ifdef SNF_HAVE_INJECT_API 214 struct pcap_snf *ps = p->priv; 215 int rc; 216 if (ps->snf_inj == NULL) { 217 rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); 218 if (rc) { 219 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 220 "snf_inject_open: %s", pcap_strerror(rc)); 221 return (-1); 222 } 223 } 224 225 rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); 226 if (!rc) { 227 return (size); 228 } 229 else { 230 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_inject_send: %s", 231 pcap_strerror(rc)); 232 return (-1); 233 } 234 #else 235 strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", 236 PCAP_ERRBUF_SIZE); 237 return (-1); 238 #endif 239 } 240 241 static int 242 snf_activate(pcap_t* p) 243 { 244 struct pcap_snf *ps = p->priv; 245 char *device = p->opt.device; 246 const char *nr = NULL; 247 int err; 248 int flags = -1, ring_id = -1; 249 250 if (device == NULL) { 251 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 252 "device is NULL: %s", pcap_strerror(errno)); 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 err = snf_open(ps->snf_boardnum, 266 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 267 NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 268 0, /* default to SNF_DATARING_SIZE from env */ 269 flags, /* may want pshared */ 270 &ps->snf_handle); 271 if (err != 0) { 272 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 273 "snf_open failed: %s", pcap_strerror(err)); 274 return -1; 275 } 276 277 if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { 278 ring_id = (int) strtol(nr, NULL, 0); 279 } 280 err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); 281 if (err != 0) { 282 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 283 "snf_ring_open_id(ring=%d) failed: %s", 284 ring_id, pcap_strerror(err)); 285 return -1; 286 } 287 288 if (p->opt.timeout <= 0) 289 ps->snf_timeout = -1; 290 else 291 ps->snf_timeout = p->opt.timeout; 292 293 err = snf_start(ps->snf_handle); 294 if (err != 0) { 295 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 296 "snf_start failed: %s", pcap_strerror(err)); 297 return -1; 298 } 299 300 /* 301 * "select()" and "poll()" don't work on snf descriptors. 302 */ 303 p->selectable_fd = -1; 304 p->linktype = DLT_EN10MB; 305 p->read_op = snf_read; 306 p->inject_op = snf_inject; 307 p->setfilter_op = snf_setfilter; 308 p->setdirection_op = NULL; /* Not implemented.*/ 309 p->set_datalink_op = snf_set_datalink; 310 p->getnonblock_op = snf_getnonblock; 311 p->setnonblock_op = snf_setnonblock; 312 p->stats_op = snf_pcap_stats; 313 p->cleanup_op = snf_platform_cleanup; 314 #ifdef SNF_HAVE_INJECT_API 315 ps->snf_inj = NULL; 316 #endif 317 return 0; 318 } 319 320 #define MAX_DESC_LENGTH 128 321 int 322 snf_findalldevs(pcap_if_t **devlistp, char *errbuf) 323 { 324 pcap_if_t *devlist = NULL,*curdev,*prevdev; 325 pcap_addr_t *curaddr; 326 struct snf_ifaddrs *ifaddrs, *ifa; 327 char desc[MAX_DESC_LENGTH]; 328 int ret; 329 330 if (snf_init(SNF_VERSION_API)) 331 return (-1); 332 333 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) 334 { 335 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 336 "snf_getifaddrs: %s", pcap_strerror(errno)); 337 return (-1); 338 } 339 ifa = ifaddrs; 340 while (ifa) 341 { 342 /* 343 * Allocate a new entry 344 */ 345 curdev = (pcap_if_t *)malloc(sizeof(pcap_if_t)); 346 if (curdev == NULL) { 347 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 348 "snf_findalldevs malloc: %s", pcap_strerror(errno)); 349 return (-1); 350 } 351 if (devlist == NULL) /* save first entry */ 352 devlist = curdev; 353 else 354 prevdev->next = curdev; 355 /* 356 * Fill in the entry. 357 */ 358 curdev->next = NULL; 359 curdev->name = strdup(ifa->snf_ifa_name); 360 if (curdev->name == NULL) { 361 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 362 "snf_findalldevs strdup: %s", pcap_strerror(errno)); 363 free(curdev); 364 return (-1); 365 } 366 (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom snf%d", 367 ifa->snf_ifa_portnum); 368 curdev->description = strdup(desc); 369 if (curdev->description == NULL) { 370 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 371 "snf_findalldevs strdup1: %s", pcap_strerror(errno)); 372 free(curdev->name); 373 free(curdev); 374 return (-1); 375 } 376 curdev->addresses = NULL; 377 curdev->flags = 0; 378 379 curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t)); 380 if (curaddr == NULL) { 381 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 382 "snf_findalldevs malloc1: %s", pcap_strerror(errno)); 383 free(curdev->description); 384 free(curdev->name); 385 free(curdev); 386 return (-1); 387 } 388 curdev->addresses = curaddr; 389 curaddr->next = NULL; 390 curaddr->addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); 391 if (curaddr->addr == NULL) { 392 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 393 "malloc2: %s", pcap_strerror(errno)); 394 free(curdev->description); 395 free(curdev->name); 396 free(curaddr); 397 free(curdev); 398 return (-1); 399 } 400 curaddr->addr->sa_family = AF_INET; 401 curaddr->netmask = NULL; 402 curaddr->broadaddr = NULL; 403 curaddr->dstaddr = NULL; 404 curaddr->next = NULL; 405 406 prevdev = curdev; 407 ifa = ifa->snf_ifa_next; 408 } 409 snf_freeifaddrs(ifaddrs); 410 *devlistp = devlist; 411 412 /* 413 * There are no platform-specific devices since each device 414 * exists as a regular Ethernet device. 415 */ 416 return 0; 417 } 418 419 pcap_t * 420 snf_create(const char *device, char *ebuf, int *is_ours) 421 { 422 pcap_t *p; 423 int boardnum = -1; 424 struct snf_ifaddrs *ifaddrs, *ifa; 425 size_t devlen; 426 struct pcap_snf *ps; 427 428 if (snf_init(SNF_VERSION_API)) { 429 /* Can't initialize the API, so no SNF devices */ 430 *is_ours = 0; 431 return NULL; 432 } 433 434 /* 435 * Match a given interface name to our list of interface names, from 436 * which we can obtain the intended board number 437 */ 438 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { 439 /* Can't get SNF addresses */ 440 *is_ours = 0; 441 return NULL; 442 } 443 devlen = strlen(device) + 1; 444 ifa = ifaddrs; 445 while (ifa) { 446 if (!strncmp(device, ifa->snf_ifa_name, devlen)) { 447 boardnum = ifa->snf_ifa_boardnum; 448 break; 449 } 450 ifa = ifa->snf_ifa_next; 451 } 452 snf_freeifaddrs(ifaddrs); 453 454 if (ifa == NULL) { 455 /* 456 * If we can't find the device by name, support the name "snfX" 457 * and "snf10gX" where X is the board number. 458 */ 459 if (sscanf(device, "snf10g%d", &boardnum) != 1 && 460 sscanf(device, "snf%d", &boardnum) != 1) { 461 /* Nope, not a supported name */ 462 *is_ours = 0; 463 return NULL; 464 } 465 } 466 467 /* OK, it's probably ours. */ 468 *is_ours = 1; 469 470 p = pcap_create_common(ebuf, sizeof (struct pcap_snf)); 471 if (p == NULL) 472 return NULL; 473 ps = p->priv; 474 475 /* 476 * We support microsecond and nanosecond time stamps. 477 */ 478 p->tstamp_precision_count = 2; 479 p->tstamp_precision_list = malloc(2 * sizeof(u_int)); 480 if (p->tstamp_precision_list == NULL) { 481 pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", 482 pcap_strerror(errno)); 483 pcap_close(p); 484 return NULL; 485 } 486 p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; 487 p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; 488 489 p->activate_op = snf_activate; 490 ps->snf_boardnum = boardnum; 491 return p; 492 } 493 494 #ifdef SNF_ONLY 495 /* 496 * This libpcap build supports only SNF cards, not regular network 497 * interfaces.. 498 */ 499 500 /* 501 * There are no regular interfaces, just DAG interfaces. 502 */ 503 int 504 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 505 { 506 *alldevsp = NULL; 507 return (0); 508 } 509 510 /* 511 * Attempts to open a regular interface fail. 512 */ 513 pcap_t * 514 pcap_create_interface(const char *device, char *errbuf) 515 { 516 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 517 "This version of libpcap only supports SNF cards"); 518 return NULL; 519 } 520 #endif 521