1335640Shselasky#ifdef HAVE_CONFIG_H 2335640Shselasky#include <config.h> 3335640Shselasky#endif 4335640Shselasky 5335640Shselasky#ifndef _WIN32 6335640Shselasky#include <sys/param.h> 7335640Shselasky#endif /* !_WIN32 */ 8335640Shselasky 9335640Shselasky#include <stdlib.h> 10335640Shselasky#include <string.h> 11335640Shselasky#include <errno.h> 12335640Shselasky 13335640Shselasky#include <ctype.h> 14335640Shselasky#ifndef _WIN32 15335640Shselasky#include <netinet/in.h> 16335640Shselasky#include <sys/mman.h> 17335640Shselasky#include <sys/socket.h> 18335640Shselasky#include <sys/types.h> 19335640Shselasky#include <unistd.h> 20335640Shselasky#endif /* !_WIN32 */ 21335640Shselasky 22335640Shselasky#include <snf.h> 23335640Shselasky#if SNF_VERSION_API >= 0x0003 24335640Shselasky#define SNF_HAVE_INJECT_API 25335640Shselasky#endif 26335640Shselasky 27335640Shselasky#include "pcap-int.h" 28335640Shselasky#include "pcap-snf.h" 29335640Shselasky 30335640Shselasky/* 31335640Shselasky * Private data for capturing on SNF devices. 32335640Shselasky */ 33335640Shselaskystruct pcap_snf { 34335640Shselasky snf_handle_t snf_handle; /* opaque device handle */ 35335640Shselasky snf_ring_t snf_ring; /* opaque device ring handle */ 36335640Shselasky#ifdef SNF_HAVE_INJECT_API 37335640Shselasky snf_inject_t snf_inj; /* inject handle, if inject is used */ 38335640Shselasky#endif 39335640Shselasky int snf_timeout; 40335640Shselasky int snf_boardnum; 41335640Shselasky}; 42335640Shselasky 43335640Shselaskystatic int 44335640Shselaskysnf_set_datalink(pcap_t *p, int dlt) 45335640Shselasky{ 46335640Shselasky p->linktype = dlt; 47335640Shselasky return (0); 48335640Shselasky} 49335640Shselasky 50335640Shselaskystatic int 51335640Shselaskysnf_pcap_stats(pcap_t *p, struct pcap_stat *ps) 52335640Shselasky{ 53335640Shselasky struct snf_ring_stats stats; 54335640Shselasky struct pcap_snf *snfps = p->priv; 55335640Shselasky int rc; 56335640Shselasky 57335640Shselasky if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { 58335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 59335640Shselasky rc, "snf_get_stats"); 60335640Shselasky return -1; 61335640Shselasky } 62335640Shselasky ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; 63335640Shselasky ps->ps_drop = stats.ring_pkt_overflow; 64335640Shselasky ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; 65335640Shselasky return 0; 66335640Shselasky} 67335640Shselasky 68335640Shselaskystatic void 69335640Shselaskysnf_platform_cleanup(pcap_t *p) 70335640Shselasky{ 71335640Shselasky struct pcap_snf *ps = p->priv; 72335640Shselasky 73335640Shselasky#ifdef SNF_HAVE_INJECT_API 74335640Shselasky if (ps->snf_inj) 75335640Shselasky snf_inject_close(ps->snf_inj); 76335640Shselasky#endif 77335640Shselasky snf_ring_close(ps->snf_ring); 78335640Shselasky snf_close(ps->snf_handle); 79335640Shselasky pcap_cleanup_live_common(p); 80335640Shselasky} 81335640Shselasky 82335640Shselaskystatic int 83335640Shselaskysnf_getnonblock(pcap_t *p) 84335640Shselasky{ 85335640Shselasky struct pcap_snf *ps = p->priv; 86335640Shselasky 87335640Shselasky return (ps->snf_timeout == 0); 88335640Shselasky} 89335640Shselasky 90335640Shselaskystatic int 91335640Shselaskysnf_setnonblock(pcap_t *p, int nonblock) 92335640Shselasky{ 93335640Shselasky struct pcap_snf *ps = p->priv; 94335640Shselasky 95335640Shselasky if (nonblock) 96335640Shselasky ps->snf_timeout = 0; 97335640Shselasky else { 98335640Shselasky if (p->opt.timeout <= 0) 99335640Shselasky ps->snf_timeout = -1; /* forever */ 100335640Shselasky else 101335640Shselasky ps->snf_timeout = p->opt.timeout; 102335640Shselasky } 103335640Shselasky return (0); 104335640Shselasky} 105335640Shselasky 106335640Shselasky#define _NSEC_PER_SEC 1000000000 107335640Shselasky 108335640Shselaskystatic inline 109335640Shselaskystruct timeval 110335640Shselaskysnf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) 111335640Shselasky{ 112335640Shselasky struct timeval tv; 113335640Shselasky long tv_nsec; 114335640Shselasky const static struct timeval zero_timeval; 115335640Shselasky 116335640Shselasky if (ts_nanosec == 0) 117335640Shselasky return zero_timeval; 118335640Shselasky 119335640Shselasky tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; 120335640Shselasky tv_nsec = (ts_nanosec % _NSEC_PER_SEC); 121335640Shselasky 122335640Shselasky /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ 123335640Shselasky if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) 124335640Shselasky tv.tv_usec = tv_nsec; 125335640Shselasky else 126335640Shselasky tv.tv_usec = tv_nsec / 1000; 127335640Shselasky 128335640Shselasky return tv; 129335640Shselasky} 130335640Shselasky 131335640Shselaskystatic int 132335640Shselaskysnf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 133335640Shselasky{ 134335640Shselasky struct pcap_snf *ps = p->priv; 135335640Shselasky struct pcap_pkthdr hdr; 136335640Shselasky int i, flags, err, caplen, n; 137335640Shselasky struct snf_recv_req req; 138335640Shselasky int nonblock, timeout; 139335640Shselasky 140335640Shselasky if (!p) 141335640Shselasky return -1; 142335640Shselasky 143335640Shselasky n = 0; 144335640Shselasky timeout = ps->snf_timeout; 145335640Shselasky while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { 146335640Shselasky /* 147335640Shselasky * Has "pcap_breakloop()" been called? 148335640Shselasky */ 149335640Shselasky if (p->break_loop) { 150335640Shselasky if (n == 0) { 151335640Shselasky p->break_loop = 0; 152335640Shselasky return (-2); 153335640Shselasky } else { 154335640Shselasky return (n); 155335640Shselasky } 156335640Shselasky } 157335640Shselasky 158335640Shselasky err = snf_ring_recv(ps->snf_ring, timeout, &req); 159335640Shselasky 160335640Shselasky if (err) { 161335640Shselasky if (err == EBUSY || err == EAGAIN) { 162335640Shselasky return (n); 163335640Shselasky } 164335640Shselasky else if (err == EINTR) { 165335640Shselasky timeout = 0; 166335640Shselasky continue; 167335640Shselasky } 168335640Shselasky else { 169335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, 170335640Shselasky PCAP_ERRBUF_SIZE, err, "snf_read"); 171335640Shselasky return -1; 172335640Shselasky } 173335640Shselasky } 174335640Shselasky 175335640Shselasky caplen = req.length; 176335640Shselasky if (caplen > p->snapshot) 177335640Shselasky caplen = p->snapshot; 178335640Shselasky 179335640Shselasky if ((p->fcode.bf_insns == NULL) || 180335640Shselasky bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 181335640Shselasky hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); 182335640Shselasky hdr.caplen = caplen; 183335640Shselasky hdr.len = req.length; 184335640Shselasky callback(user, &hdr, req.pkt_addr); 185356341Scy n++; 186335640Shselasky } 187335640Shselasky 188335640Shselasky /* After one successful packet is received, we won't block 189335640Shselasky * again for that timeout. */ 190335640Shselasky if (timeout != 0) 191335640Shselasky timeout = 0; 192335640Shselasky } 193335640Shselasky return (n); 194335640Shselasky} 195335640Shselasky 196335640Shselaskystatic int 197335640Shselaskysnf_setfilter(pcap_t *p, struct bpf_program *fp) 198335640Shselasky{ 199335640Shselasky if (!p) 200335640Shselasky return -1; 201335640Shselasky if (!fp) { 202335640Shselasky strncpy(p->errbuf, "setfilter: No filter specified", 203335640Shselasky sizeof(p->errbuf)); 204335640Shselasky return -1; 205335640Shselasky } 206335640Shselasky 207335640Shselasky /* Make our private copy of the filter */ 208335640Shselasky 209335640Shselasky if (install_bpf_program(p, fp) < 0) 210335640Shselasky return -1; 211335640Shselasky 212335640Shselasky return (0); 213335640Shselasky} 214335640Shselasky 215335640Shselaskystatic int 216335640Shselaskysnf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 217335640Shselasky{ 218335640Shselasky#ifdef SNF_HAVE_INJECT_API 219335640Shselasky struct pcap_snf *ps = p->priv; 220335640Shselasky int rc; 221335640Shselasky if (ps->snf_inj == NULL) { 222335640Shselasky rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); 223335640Shselasky if (rc) { 224335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 225335640Shselasky rc, "snf_inject_open"); 226335640Shselasky return (-1); 227335640Shselasky } 228335640Shselasky } 229335640Shselasky 230335640Shselasky rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); 231335640Shselasky if (!rc) { 232335640Shselasky return (size); 233335640Shselasky } 234335640Shselasky else { 235335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 236335640Shselasky rc, "snf_inject_send"); 237335640Shselasky return (-1); 238335640Shselasky } 239335640Shselasky#else 240356341Scy pcap_strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", 241335640Shselasky PCAP_ERRBUF_SIZE); 242335640Shselasky return (-1); 243335640Shselasky#endif 244335640Shselasky} 245335640Shselasky 246335640Shselaskystatic int 247335640Shselaskysnf_activate(pcap_t* p) 248335640Shselasky{ 249335640Shselasky struct pcap_snf *ps = p->priv; 250335640Shselasky char *device = p->opt.device; 251335640Shselasky const char *nr = NULL; 252335640Shselasky int err; 253335640Shselasky int flags = -1, ring_id = -1; 254335640Shselasky 255335640Shselasky if (device == NULL) { 256335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); 257335640Shselasky return -1; 258335640Shselasky } 259335640Shselasky 260335640Shselasky /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. 261335640Shselasky * Since libpcap isn't thread-safe */ 262335640Shselasky if ((nr = getenv("SNF_FLAGS")) && *nr) 263335640Shselasky flags = strtol(nr, NULL, 0); 264335640Shselasky else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) 265335640Shselasky flags = SNF_F_PSHARED; 266335640Shselasky else 267335640Shselasky nr = NULL; 268335640Shselasky 269335640Shselasky 270335640Shselasky /* Allow pcap_set_buffer_size() to set dataring_size. 271335640Shselasky * Default is zero which allows setting from env SNF_DATARING_SIZE. 272335640Shselasky * pcap_set_buffer_size() is in bytes while snf_open() accepts values 273335640Shselasky * between 0 and 1048576 in Megabytes. Values in this range are 274335640Shselasky * mapped to 1MB. 275335640Shselasky */ 276335640Shselasky err = snf_open(ps->snf_boardnum, 277335640Shselasky 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 278335640Shselasky NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 279335640Shselasky (p->opt.buffer_size > 0 && p->opt.buffer_size < 1048576) ? 1048576 : p->opt.buffer_size, /* default to SNF_DATARING_SIZE from env */ 280335640Shselasky flags, /* may want pshared */ 281335640Shselasky &ps->snf_handle); 282335640Shselasky if (err != 0) { 283335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 284335640Shselasky err, "snf_open failed"); 285335640Shselasky return -1; 286335640Shselasky } 287335640Shselasky 288335640Shselasky if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { 289335640Shselasky ring_id = (int) strtol(nr, NULL, 0); 290335640Shselasky } 291335640Shselasky err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); 292335640Shselasky if (err != 0) { 293335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 294335640Shselasky err, "snf_ring_open_id(ring=%d) failed", ring_id); 295335640Shselasky return -1; 296335640Shselasky } 297335640Shselasky 298335640Shselasky /* 299335640Shselasky * Turn a negative snapshot value (invalid), a snapshot value of 300335640Shselasky * 0 (unspecified), or a value bigger than the normal maximum 301335640Shselasky * value, into the maximum allowed value. 302335640Shselasky * 303335640Shselasky * If some application really *needs* a bigger snapshot 304335640Shselasky * length, we should just increase MAXIMUM_SNAPLEN. 305335640Shselasky */ 306335640Shselasky if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 307335640Shselasky p->snapshot = MAXIMUM_SNAPLEN; 308335640Shselasky 309335640Shselasky if (p->opt.timeout <= 0) 310335640Shselasky ps->snf_timeout = -1; 311335640Shselasky else 312335640Shselasky ps->snf_timeout = p->opt.timeout; 313335640Shselasky 314335640Shselasky err = snf_start(ps->snf_handle); 315335640Shselasky if (err != 0) { 316335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 317335640Shselasky err, "snf_start failed"); 318335640Shselasky return -1; 319335640Shselasky } 320335640Shselasky 321335640Shselasky /* 322335640Shselasky * "select()" and "poll()" don't work on snf descriptors. 323335640Shselasky */ 324335640Shselasky#ifndef _WIN32 325335640Shselasky p->selectable_fd = -1; 326335640Shselasky#endif /* !_WIN32 */ 327335640Shselasky p->linktype = DLT_EN10MB; 328335640Shselasky p->read_op = snf_read; 329335640Shselasky p->inject_op = snf_inject; 330335640Shselasky p->setfilter_op = snf_setfilter; 331335640Shselasky p->setdirection_op = NULL; /* Not implemented.*/ 332335640Shselasky p->set_datalink_op = snf_set_datalink; 333335640Shselasky p->getnonblock_op = snf_getnonblock; 334335640Shselasky p->setnonblock_op = snf_setnonblock; 335335640Shselasky p->stats_op = snf_pcap_stats; 336335640Shselasky p->cleanup_op = snf_platform_cleanup; 337335640Shselasky#ifdef SNF_HAVE_INJECT_API 338335640Shselasky ps->snf_inj = NULL; 339335640Shselasky#endif 340335640Shselasky return 0; 341335640Shselasky} 342335640Shselasky 343335640Shselasky#define MAX_DESC_LENGTH 128 344335640Shselaskyint 345335640Shselaskysnf_findalldevs(pcap_if_list_t *devlistp, char *errbuf) 346335640Shselasky{ 347335640Shselasky pcap_if_t *dev; 348335640Shselasky#ifdef _WIN32 349335640Shselasky struct sockaddr_in addr; 350335640Shselasky#endif 351335640Shselasky struct snf_ifaddrs *ifaddrs, *ifa; 352335640Shselasky char name[MAX_DESC_LENGTH]; 353335640Shselasky char desc[MAX_DESC_LENGTH]; 354335640Shselasky int ret, allports = 0, merge = 0; 355335640Shselasky const char *nr = NULL; 356335640Shselasky 357335640Shselasky if (snf_init(SNF_VERSION_API)) { 358335640Shselasky (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 359335640Shselasky "snf_getifaddrs: snf_init failed"); 360335640Shselasky return (-1); 361335640Shselasky } 362335640Shselasky 363335640Shselasky if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) 364335640Shselasky { 365335640Shselasky pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 366335640Shselasky errno, "snf_getifaddrs"); 367335640Shselasky return (-1); 368335640Shselasky } 369335640Shselasky if ((nr = getenv("SNF_FLAGS")) && *nr) { 370335640Shselasky errno = 0; 371335640Shselasky merge = strtol(nr, NULL, 0); 372335640Shselasky if (errno) { 373335640Shselasky (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 374335640Shselasky "snf_getifaddrs: SNF_FLAGS is not a valid number"); 375335640Shselasky return (-1); 376335640Shselasky } 377335640Shselasky merge = merge & SNF_F_AGGREGATE_PORTMASK; 378335640Shselasky } 379335640Shselasky 380335640Shselasky for (ifa = ifaddrs; ifa != NULL; ifa = ifa->snf_ifa_next) { 381335640Shselasky /* 382335640Shselasky * Myricom SNF adapter ports may appear as regular 383335640Shselasky * network interfaces, which would already have been 384335640Shselasky * added to the list of adapters by pcap_platform_finddevs() 385335640Shselasky * if this isn't an SNF-only version of libpcap. 386335640Shselasky * 387335640Shselasky * Our create routine intercepts pcap_create() calls for 388335640Shselasky * those interfaces and arranges that they will be 389335640Shselasky * opened using the SNF API instead. 390335640Shselasky * 391335640Shselasky * So if we already have an entry for the device, we 392335640Shselasky * don't add an additional entry for it, we just 393335640Shselasky * update the description for it, if any, to indicate 394335640Shselasky * which snfN device it is. Otherwise, we add an entry 395335640Shselasky * for it. 396335640Shselasky * 397335640Shselasky * In either case, if SNF_F_AGGREGATE_PORTMASK is set 398335640Shselasky * in SNF_FLAGS, we add this port to the bitmask 399335640Shselasky * of ports, which we use to generate a device 400335640Shselasky * we can use to capture on all ports. 401335640Shselasky * 402335640Shselasky * Generate the description string. If port aggregation 403335640Shselasky * is set, use 2^{port number} as the unit number, 404335640Shselasky * rather than {port number}. 405335640Shselasky * 406335640Shselasky * XXX - do entries in this list have IP addresses for 407335640Shselasky * the port? If so, should we add them to the 408335640Shselasky * entry for the device, if they're not already in the 409335640Shselasky * list of IP addresses for the device? 410335640Shselasky */ 411335640Shselasky (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d", 412335640Shselasky merge ? "Merge Bitmask Port " : "", 413335640Shselasky merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum); 414335640Shselasky /* 415335640Shselasky * Add the port to the bitmask. 416335640Shselasky */ 417335640Shselasky if (merge) 418335640Shselasky allports |= 1 << ifa->snf_ifa_portnum; 419335640Shselasky /* 420335640Shselasky * See if there's already an entry for the device 421335640Shselasky * with the name ifa->snf_ifa_name. 422335640Shselasky */ 423335640Shselasky dev = find_dev(devlistp, ifa->snf_ifa_name); 424335640Shselasky if (dev != NULL) { 425335640Shselasky /* 426335640Shselasky * Yes. Update its description. 427335640Shselasky */ 428335640Shselasky char *desc_str; 429335640Shselasky 430335640Shselasky desc_str = strdup(desc); 431335640Shselasky if (desc_str == NULL) { 432335640Shselasky pcap_fmt_errmsg_for_errno(errbuf, 433335640Shselasky PCAP_ERRBUF_SIZE, errno, 434335640Shselasky "snf_findalldevs strdup"); 435335640Shselasky return -1; 436335640Shselasky } 437335640Shselasky free(dev->description); 438335640Shselasky dev->description = desc_str; 439335640Shselasky } else { 440335640Shselasky /* 441335640Shselasky * No. Add an entry for it. 442335640Shselasky * 443335640Shselasky * XXX - is there a notion of "up" or "running", 444335640Shselasky * and can we determine whether something's 445335640Shselasky * plugged into the adapter and set 446335640Shselasky * PCAP_IF_CONNECTION_STATUS_CONNECTED or 447335640Shselasky * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? 448335640Shselasky */ 449335640Shselasky dev = add_dev(devlistp, ifa->snf_ifa_name, 0, desc, 450335640Shselasky errbuf); 451335640Shselasky if (dev == NULL) 452335640Shselasky return -1; 453335640Shselasky#ifdef _WIN32 454335640Shselasky /* 455335640Shselasky * On Windows, fill in IP# from device name 456335640Shselasky */ 457335640Shselasky ret = inet_pton(AF_INET, dev->name, &addr.sin_addr); 458335640Shselasky if (ret == 1) { 459335640Shselasky /* 460335640Shselasky * Successful conversion of device name 461335640Shselasky * to IPv4 address. 462335640Shselasky */ 463335640Shselasky addr.sin_family = AF_INET; 464335640Shselasky if (add_addr_to_dev(dev, &addr, sizeof(addr), 465335640Shselasky NULL, 0, NULL, 0, NULL, 0, errbuf) == -1) 466335640Shselasky return -1; 467335640Shselasky } else if (ret == -1) { 468335640Shselasky /* 469335640Shselasky * Error. 470335640Shselasky */ 471335640Shselasky pcap_fmt_errmsg_for_errno(errbuf, 472335640Shselasky PCAP_ERRBUF_SIZE, errno, 473335640Shselasky "sinf_findalldevs inet_pton"); 474335640Shselasky return -1; 475335640Shselasky } 476335640Shselasky#endif _WIN32 477335640Shselasky } 478335640Shselasky } 479335640Shselasky snf_freeifaddrs(ifaddrs); 480335640Shselasky /* 481335640Shselasky * Create a snfX entry if port aggregation is enabled 482335640Shselasky */ 483335640Shselasky if (merge) { 484335640Shselasky /* 485335640Shselasky * Add a new entry with all ports bitmask 486335640Shselasky */ 487335640Shselasky (void)pcap_snprintf(name,MAX_DESC_LENGTH,"snf%d",allports); 488335640Shselasky (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d", 489335640Shselasky allports); 490335640Shselasky /* 491335640Shselasky * XXX - is there any notion of "up" and "running" that 492335640Shselasky * would apply to this device, given that it handles 493335640Shselasky * multiple ports? 494335640Shselasky * 495335640Shselasky * Presumably, there's no notion of "connected" vs. 496335640Shselasky * "disconnected", as "is this plugged into a network?" 497335640Shselasky * would be a per-port property. 498335640Shselasky */ 499335640Shselasky if (add_dev(devlistp, name, 500335640Shselasky PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc, 501335640Shselasky errbuf) == NULL) 502335640Shselasky return (-1); 503335640Shselasky /* 504335640Shselasky * XXX - should we give it a list of addresses with all 505335640Shselasky * the addresses for all the ports? 506335640Shselasky */ 507335640Shselasky } 508335640Shselasky 509335640Shselasky return 0; 510335640Shselasky} 511335640Shselasky 512335640Shselaskypcap_t * 513335640Shselaskysnf_create(const char *device, char *ebuf, int *is_ours) 514335640Shselasky{ 515335640Shselasky pcap_t *p; 516335640Shselasky int boardnum = -1; 517335640Shselasky struct snf_ifaddrs *ifaddrs, *ifa; 518335640Shselasky size_t devlen; 519335640Shselasky struct pcap_snf *ps; 520335640Shselasky 521335640Shselasky if (snf_init(SNF_VERSION_API)) { 522335640Shselasky /* Can't initialize the API, so no SNF devices */ 523335640Shselasky *is_ours = 0; 524335640Shselasky return NULL; 525335640Shselasky } 526335640Shselasky 527335640Shselasky /* 528335640Shselasky * Match a given interface name to our list of interface names, from 529335640Shselasky * which we can obtain the intended board number 530335640Shselasky */ 531335640Shselasky if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { 532335640Shselasky /* Can't get SNF addresses */ 533335640Shselasky *is_ours = 0; 534335640Shselasky return NULL; 535335640Shselasky } 536335640Shselasky devlen = strlen(device) + 1; 537335640Shselasky ifa = ifaddrs; 538335640Shselasky while (ifa) { 539335640Shselasky if (strncmp(device, ifa->snf_ifa_name, devlen) == 0) { 540335640Shselasky boardnum = ifa->snf_ifa_boardnum; 541335640Shselasky break; 542335640Shselasky } 543335640Shselasky ifa = ifa->snf_ifa_next; 544335640Shselasky } 545335640Shselasky snf_freeifaddrs(ifaddrs); 546335640Shselasky 547335640Shselasky if (ifa == NULL) { 548335640Shselasky /* 549335640Shselasky * If we can't find the device by name, support the name "snfX" 550335640Shselasky * and "snf10gX" where X is the board number. 551335640Shselasky */ 552335640Shselasky if (sscanf(device, "snf10g%d", &boardnum) != 1 && 553335640Shselasky sscanf(device, "snf%d", &boardnum) != 1) { 554335640Shselasky /* Nope, not a supported name */ 555335640Shselasky *is_ours = 0; 556335640Shselasky return NULL; 557335640Shselasky } 558335640Shselasky } 559335640Shselasky 560335640Shselasky /* OK, it's probably ours. */ 561335640Shselasky *is_ours = 1; 562335640Shselasky 563335640Shselasky p = pcap_create_common(ebuf, sizeof (struct pcap_snf)); 564335640Shselasky if (p == NULL) 565335640Shselasky return NULL; 566335640Shselasky ps = p->priv; 567335640Shselasky 568335640Shselasky /* 569335640Shselasky * We support microsecond and nanosecond time stamps. 570335640Shselasky */ 571335640Shselasky p->tstamp_precision_count = 2; 572335640Shselasky p->tstamp_precision_list = malloc(2 * sizeof(u_int)); 573335640Shselasky if (p->tstamp_precision_list == NULL) { 574335640Shselasky pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, 575335640Shselasky "malloc"); 576335640Shselasky pcap_close(p); 577335640Shselasky return NULL; 578335640Shselasky } 579335640Shselasky p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; 580335640Shselasky p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; 581335640Shselasky 582335640Shselasky p->activate_op = snf_activate; 583335640Shselasky ps->snf_boardnum = boardnum; 584335640Shselasky return p; 585335640Shselasky} 586335640Shselasky 587335640Shselasky#ifdef SNF_ONLY 588335640Shselasky/* 589335640Shselasky * This libpcap build supports only SNF cards, not regular network 590335640Shselasky * interfaces.. 591335640Shselasky */ 592335640Shselasky 593335640Shselasky/* 594335640Shselasky * There are no regular interfaces, just SNF interfaces. 595335640Shselasky */ 596335640Shselaskyint 597335640Shselaskypcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 598335640Shselasky{ 599335640Shselasky return (0); 600335640Shselasky} 601335640Shselasky 602335640Shselasky/* 603335640Shselasky * Attempts to open a regular interface fail. 604335640Shselasky */ 605335640Shselaskypcap_t * 606335640Shselaskypcap_create_interface(const char *device, char *errbuf) 607335640Shselasky{ 608335640Shselasky pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 609335640Shselasky "This version of libpcap only supports SNF cards"); 610335640Shselasky return NULL; 611335640Shselasky} 612335640Shselasky 613335640Shselasky/* 614335640Shselasky * Libpcap version string. 615335640Shselasky */ 616335640Shselaskyconst char * 617335640Shselaskypcap_lib_version(void) 618335640Shselasky{ 619335640Shselasky return (PCAP_VERSION_STRING " (SNF-only)"); 620335640Shselasky} 621335640Shselasky#endif 622