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 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 if (p == NULL) 70 return; 71 72 #ifdef SNF_HAVE_INJECT_API 73 if (ps->snf_inj) 74 snf_inject_close(ps->snf_inj); 75 #endif 76 snf_ring_close(ps->snf_ring); 77 snf_close(ps->snf_handle); 78 pcap_cleanup_live_common(p); 79 } 80 81 static int 82 snf_getnonblock(pcap_t *p, char *errbuf) 83 { 84 struct pcap_snf *ps = p->priv; 85 86 return (ps->snf_timeout == 0); 87 } 88 89 static int 90 snf_setnonblock(pcap_t *p, int nonblock, char *errbuf) 91 { 92 struct pcap_snf *ps = p->priv; 93 94 if (nonblock) 95 ps->snf_timeout = 0; 96 else { 97 if (p->opt.timeout <= 0) 98 ps->snf_timeout = -1; /* forever */ 99 else 100 ps->snf_timeout = p->opt.timeout; 101 } 102 return (0); 103 } 104 105 #define _NSEC_PER_SEC 1000000000 106 107 static inline 108 struct timeval 109 snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) 110 { 111 struct timeval tv; 112 long tv_nsec; 113 114 if (ts_nanosec == 0) 115 return (struct timeval) { 0, 0 }; 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 n = 0; 142 timeout = ps->snf_timeout; 143 while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { 144 /* 145 * Has "pcap_breakloop()" been called? 146 */ 147 if (p->break_loop) { 148 if (n == 0) { 149 p->break_loop = 0; 150 return (-2); 151 } else { 152 return (n); 153 } 154 } 155 156 err = snf_ring_recv(ps->snf_ring, timeout, &req); 157 158 if (err) { 159 if (err == EBUSY || err == EAGAIN) { 160 return (n); 161 } 162 else if (err == EINTR) { 163 timeout = 0; 164 continue; 165 } 166 else { 167 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", 168 pcap_strerror(err)); 169 return -1; 170 } 171 } 172 173 caplen = req.length; 174 if (caplen > p->snapshot) 175 caplen = p->snapshot; 176 177 if ((p->fcode.bf_insns == NULL) || 178 bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 179 hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); 180 hdr.caplen = caplen; 181 hdr.len = req.length; 182 callback(user, &hdr, req.pkt_addr); 183 } 184 n++; 185 186 /* After one successful packet is received, we won't block 187 * again for that timeout. */ 188 if (timeout != 0) 189 timeout = 0; 190 } 191 return (n); 192 } 193 194 static int 195 snf_setfilter(pcap_t *p, struct bpf_program *fp) 196 { 197 if (!p) 198 return -1; 199 if (!fp) { 200 strncpy(p->errbuf, "setfilter: No filter specified", 201 sizeof(p->errbuf)); 202 return -1; 203 } 204 205 /* Make our private copy of the filter */ 206 207 if (install_bpf_program(p, fp) < 0) 208 return -1; 209 210 return (0); 211 } 212 213 static int 214 snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 215 { 216 #ifdef SNF_HAVE_INJECT_API 217 struct pcap_snf *ps = p->priv; 218 int rc; 219 if (ps->snf_inj == NULL) { 220 rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); 221 if (rc) { 222 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 223 "snf_inject_open: %s", pcap_strerror(rc)); 224 return (-1); 225 } 226 } 227 228 rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); 229 if (!rc) { 230 return (size); 231 } 232 else { 233 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_inject_send: %s", 234 pcap_strerror(rc)); 235 return (-1); 236 } 237 #else 238 strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", 239 PCAP_ERRBUF_SIZE); 240 return (-1); 241 #endif 242 } 243 244 static int 245 snf_activate(pcap_t* p) 246 { 247 struct pcap_snf *ps = p->priv; 248 char *device = p->opt.source; 249 const char *nr = NULL; 250 int err; 251 int flags = -1, ring_id = -1; 252 253 if (device == NULL) { 254 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 255 "device is NULL: %s", pcap_strerror(errno)); 256 return -1; 257 } 258 259 /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. 260 * Since libpcap isn't thread-safe */ 261 if ((nr = getenv("SNF_FLAGS")) && *nr) 262 flags = strtol(nr, NULL, 0); 263 else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) 264 flags = SNF_F_PSHARED; 265 else 266 nr = NULL; 267 268 err = snf_open(ps->snf_boardnum, 269 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 270 NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 271 0, /* default to SNF_DATARING_SIZE from env */ 272 flags, /* may want pshared */ 273 &ps->snf_handle); 274 if (err != 0) { 275 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 276 "snf_open failed: %s", pcap_strerror(err)); 277 return -1; 278 } 279 280 if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { 281 ring_id = (int) strtol(nr, NULL, 0); 282 } 283 err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); 284 if (err != 0) { 285 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 286 "snf_ring_open_id(ring=%d) failed: %s", 287 ring_id, pcap_strerror(err)); 288 return -1; 289 } 290 291 if (p->opt.timeout <= 0) 292 ps->snf_timeout = -1; 293 else 294 ps->snf_timeout = p->opt.timeout; 295 296 err = snf_start(ps->snf_handle); 297 if (err != 0) { 298 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 299 "snf_start failed: %s", pcap_strerror(err)); 300 return -1; 301 } 302 303 /* 304 * "select()" and "poll()" don't work on snf descriptors. 305 */ 306 p->selectable_fd = -1; 307 p->linktype = DLT_EN10MB; 308 p->read_op = snf_read; 309 p->inject_op = snf_inject; 310 p->setfilter_op = snf_setfilter; 311 p->setdirection_op = NULL; /* Not implemented.*/ 312 p->set_datalink_op = snf_set_datalink; 313 p->getnonblock_op = snf_getnonblock; 314 p->setnonblock_op = snf_setnonblock; 315 p->stats_op = snf_pcap_stats; 316 p->cleanup_op = snf_platform_cleanup; 317 #ifdef SNF_HAVE_INJECT_API 318 ps->snf_inj = NULL; 319 #endif 320 return 0; 321 } 322 323 #define MAX_DESC_LENGTH 128 324 int 325 snf_findalldevs(pcap_if_t **devlistp, char *errbuf) 326 { 327 pcap_if_t *devlist = NULL,*curdev,*prevdev; 328 pcap_addr_t *curaddr; 329 struct snf_ifaddrs *ifaddrs, *ifa; 330 char desc[MAX_DESC_LENGTH]; 331 int ret; 332 333 if (snf_init(SNF_VERSION_API)) 334 return (-1); 335 336 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) 337 { 338 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 339 "snf_getifaddrs: %s", pcap_strerror(errno)); 340 return (-1); 341 } 342 ifa = ifaddrs; 343 while (ifa) 344 { 345 /* 346 * Allocate a new entry 347 */ 348 curdev = (pcap_if_t *)malloc(sizeof(pcap_if_t)); 349 if (curdev == NULL) { 350 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 351 "snf_findalldevs malloc: %s", pcap_strerror(errno)); 352 return (-1); 353 } 354 if (devlist == NULL) /* save first entry */ 355 devlist = curdev; 356 else 357 prevdev->next = curdev; 358 /* 359 * Fill in the entry. 360 */ 361 curdev->next = NULL; 362 curdev->name = strdup(ifa->snf_ifa_name); 363 if (curdev->name == NULL) { 364 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 365 "snf_findalldevs strdup: %s", pcap_strerror(errno)); 366 free(curdev); 367 return (-1); 368 } 369 (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom snf%d", 370 ifa->snf_ifa_portnum); 371 curdev->description = strdup(desc); 372 if (curdev->description == NULL) { 373 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 374 "snf_findalldevs strdup1: %s", pcap_strerror(errno)); 375 free(curdev->name); 376 free(curdev); 377 return (-1); 378 } 379 curdev->addresses = NULL; 380 curdev->flags = 0; 381 382 curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t)); 383 if (curaddr == NULL) { 384 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 385 "snf_findalldevs malloc1: %s", pcap_strerror(errno)); 386 free(curdev->description); 387 free(curdev->name); 388 free(curdev); 389 return (-1); 390 } 391 curdev->addresses = curaddr; 392 curaddr->next = NULL; 393 curaddr->addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); 394 if (curaddr->addr == NULL) { 395 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 396 "malloc2: %s", pcap_strerror(errno)); 397 free(curdev->description); 398 free(curdev->name); 399 free(curaddr); 400 free(curdev); 401 return (-1); 402 } 403 curaddr->addr->sa_family = AF_INET; 404 curaddr->netmask = NULL; 405 curaddr->broadaddr = NULL; 406 curaddr->dstaddr = NULL; 407 curaddr->next = NULL; 408 409 prevdev = curdev; 410 ifa = ifa->snf_ifa_next; 411 } 412 snf_freeifaddrs(ifaddrs); 413 *devlistp = devlist; 414 415 /* 416 * There are no platform-specific devices since each device 417 * exists as a regular Ethernet device. 418 */ 419 return 0; 420 } 421 422 pcap_t * 423 snf_create(const char *device, char *ebuf, int *is_ours) 424 { 425 pcap_t *p; 426 int boardnum = -1; 427 struct snf_ifaddrs *ifaddrs, *ifa; 428 size_t devlen; 429 struct pcap_snf *ps; 430 431 if (snf_init(SNF_VERSION_API)) { 432 /* Can't initialize the API, so no SNF devices */ 433 *is_ours = 0; 434 return NULL; 435 } 436 437 /* 438 * Match a given interface name to our list of interface names, from 439 * which we can obtain the intended board number 440 */ 441 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { 442 /* Can't get SNF addresses */ 443 *is_ours = 0; 444 return NULL; 445 } 446 devlen = strlen(device) + 1; 447 ifa = ifaddrs; 448 while (ifa) { 449 if (!strncmp(device, ifa->snf_ifa_name, devlen)) { 450 boardnum = ifa->snf_ifa_boardnum; 451 break; 452 } 453 ifa = ifa->snf_ifa_next; 454 } 455 snf_freeifaddrs(ifaddrs); 456 457 if (ifa == NULL) { 458 /* 459 * If we can't find the device by name, support the name "snfX" 460 * and "snf10gX" where X is the board number. 461 */ 462 if (sscanf(device, "snf10g%d", &boardnum) != 1 && 463 sscanf(device, "snf%d", &boardnum) != 1) { 464 /* Nope, not a supported name */ 465 *is_ours = 0; 466 return NULL; 467 } 468 } 469 470 /* OK, it's probably ours. */ 471 *is_ours = 1; 472 473 p = pcap_create_common(device, ebuf, sizeof (struct pcap_snf)); 474 if (p == NULL) 475 return NULL; 476 ps = p->priv; 477 478 /* 479 * We support microsecond and nanosecond time stamps. 480 */ 481 p->tstamp_precision_count = 2; 482 p->tstamp_precision_list = malloc(2 * sizeof(u_int)); 483 if (p->tstamp_precision_list == NULL) { 484 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", 485 pcap_strerror(errno)); 486 if (p->tstamp_type_list != NULL) 487 free(p->tstamp_type_list); 488 free(p); 489 return NULL; 490 } 491 p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; 492 p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; 493 494 p->activate_op = snf_activate; 495 ps->snf_boardnum = boardnum; 496 return p; 497 } 498