1214455Srpaulo#ifdef HAVE_CONFIG_H 2214455Srpaulo#include "config.h" 3214455Srpaulo#endif 4214455Srpaulo 5214455Srpaulo#include <sys/param.h> 6214455Srpaulo 7214455Srpaulo#include <stdlib.h> 8214455Srpaulo#include <string.h> 9214455Srpaulo#include <errno.h> 10214455Srpaulo 11214455Srpaulo#include <ctype.h> 12214455Srpaulo#include <netinet/in.h> 13214455Srpaulo#include <sys/mman.h> 14214455Srpaulo#include <sys/socket.h> 15214455Srpaulo#include <sys/types.h> 16214455Srpaulo#include <unistd.h> 17214455Srpaulo 18214455Srpaulo#include "snf.h" 19214455Srpaulo#include "pcap-int.h" 20214455Srpaulo 21214455Srpaulostatic int 22214455Srpaulosnf_set_datalink(pcap_t *p, int dlt) 23214455Srpaulo{ 24214455Srpaulo p->linktype = dlt; 25214455Srpaulo return (0); 26214455Srpaulo} 27214455Srpaulo 28214455Srpaulostatic int 29214455Srpaulosnf_pcap_stats(pcap_t *p, struct pcap_stat *ps) 30214455Srpaulo{ 31214455Srpaulo struct snf_ring_stats stats; 32214455Srpaulo int rc; 33214455Srpaulo 34214455Srpaulo if ((rc = snf_ring_getstats(p->md.snf_ring, &stats))) { 35214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", 36214455Srpaulo pcap_strerror(rc)); 37214455Srpaulo return -1; 38214455Srpaulo } 39214455Srpaulo ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; 40214455Srpaulo ps->ps_drop = stats.ring_pkt_overflow; 41214455Srpaulo ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; 42214455Srpaulo return 0; 43214455Srpaulo} 44214455Srpaulo 45214455Srpaulostatic void 46214455Srpaulosnf_platform_cleanup(pcap_t *p) 47214455Srpaulo{ 48214455Srpaulo if (p == NULL) 49214455Srpaulo return; 50214455Srpaulo 51214455Srpaulo snf_ring_close(p->md.snf_ring); 52214455Srpaulo snf_close(p->md.snf_handle); 53214455Srpaulo pcap_cleanup_live_common(p); 54214455Srpaulo} 55214455Srpaulo 56214455Srpaulostatic int 57214455Srpaulosnf_getnonblock(pcap_t *p, char *errbuf) 58214455Srpaulo{ 59214455Srpaulo return (p->md.snf_timeout == 0); 60214455Srpaulo} 61214455Srpaulo 62214455Srpaulostatic int 63214455Srpaulosnf_setnonblock(pcap_t *p, int nonblock, char *errbuf) 64214455Srpaulo{ 65214455Srpaulo if (nonblock) 66214455Srpaulo p->md.snf_timeout = 0; 67214455Srpaulo else { 68214455Srpaulo if (p->md.timeout <= 0) 69214455Srpaulo p->md.snf_timeout = -1; /* forever */ 70214455Srpaulo else 71214455Srpaulo p->md.snf_timeout = p->md.timeout; 72214455Srpaulo } 73214455Srpaulo return (0); 74214455Srpaulo} 75214455Srpaulo 76214455Srpaulo#define _NSEC_PER_SEC 1000000000 77214455Srpaulo 78214455Srpaulostatic inline 79214455Srpaulostruct timeval 80214455Srpaulosnf_timestamp_to_timeval(const int64_t ts_nanosec) 81214455Srpaulo{ 82214455Srpaulo struct timeval tv; 83214455Srpaulo int32_t rem; 84214455Srpaulo if (ts_nanosec == 0) 85214455Srpaulo return (struct timeval) { 0, 0 }; 86214455Srpaulo tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; 87214455Srpaulo tv.tv_usec = (ts_nanosec % _NSEC_PER_SEC) / 1000; 88214455Srpaulo return tv; 89214455Srpaulo} 90214455Srpaulo 91214455Srpaulostatic int 92214455Srpaulosnf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 93214455Srpaulo{ 94214455Srpaulo struct pcap_pkthdr hdr; 95214455Srpaulo int i, flags, err, caplen, n; 96214455Srpaulo struct snf_recv_req req; 97214455Srpaulo 98214455Srpaulo if (!p || cnt == 0) 99214455Srpaulo return -1; 100214455Srpaulo 101214455Srpaulo n = 0; 102214455Srpaulo while (n < cnt || cnt < 0) { 103214455Srpaulo /* 104214455Srpaulo * Has "pcap_breakloop()" been called? 105214455Srpaulo */ 106214455Srpaulo if (p->break_loop) { 107214455Srpaulo if (n == 0) { 108214455Srpaulo p->break_loop = 0; 109214455Srpaulo return (-2); 110214455Srpaulo } else { 111214455Srpaulo return (n); 112214455Srpaulo } 113214455Srpaulo } 114214455Srpaulo 115214455Srpaulo err = snf_ring_recv(p->md.snf_ring, p->md.snf_timeout, &req); 116214455Srpaulo 117214455Srpaulo if (err) { 118214455Srpaulo if (err == EBUSY || err == EAGAIN) 119214455Srpaulo return (0); 120214455Srpaulo if (err == EINTR) 121214455Srpaulo continue; 122214455Srpaulo if (err != 0) { 123214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", 124214455Srpaulo pcap_strerror(err)); 125214455Srpaulo return -1; 126214455Srpaulo } 127214455Srpaulo } 128214455Srpaulo 129214455Srpaulo caplen = req.length; 130214455Srpaulo if (caplen > p->snapshot) 131214455Srpaulo caplen = p->snapshot; 132214455Srpaulo 133214455Srpaulo if ((p->fcode.bf_insns == NULL) || 134214455Srpaulo bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 135214455Srpaulo hdr.ts = snf_timestamp_to_timeval(req.timestamp); 136214455Srpaulo hdr.caplen = caplen; 137214455Srpaulo hdr.len = req.length; 138214455Srpaulo callback(user, &hdr, req.pkt_addr); 139214455Srpaulo } 140214455Srpaulo n++; 141214455Srpaulo } 142214455Srpaulo return (n); 143214455Srpaulo} 144214455Srpaulo 145214455Srpaulostatic int 146214455Srpaulosnf_setfilter(pcap_t *p, struct bpf_program *fp) 147214455Srpaulo{ 148214455Srpaulo if (!p) 149214455Srpaulo return -1; 150214455Srpaulo if (!fp) { 151214455Srpaulo strncpy(p->errbuf, "setfilter: No filter specified", 152214455Srpaulo sizeof(p->errbuf)); 153214455Srpaulo return -1; 154214455Srpaulo } 155214455Srpaulo 156214455Srpaulo /* Make our private copy of the filter */ 157214455Srpaulo 158214455Srpaulo if (install_bpf_program(p, fp) < 0) 159214455Srpaulo return -1; 160214455Srpaulo 161214455Srpaulo p->md.use_bpf = 0; 162214455Srpaulo 163214455Srpaulo return (0); 164214455Srpaulo} 165214455Srpaulo 166214455Srpaulostatic int 167214455Srpaulosnf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 168214455Srpaulo{ 169214455Srpaulo strlcpy(p->errbuf, "Sending packets isn't supported with snf", 170214455Srpaulo PCAP_ERRBUF_SIZE); 171214455Srpaulo return (-1); 172214455Srpaulo} 173214455Srpaulo 174214455Srpaulostatic int 175214455Srpaulosnf_activate(pcap_t* p) 176214455Srpaulo{ 177214455Srpaulo char *device = p->opt.source; 178214455Srpaulo const char *nr = NULL; 179214455Srpaulo int err; 180214455Srpaulo int flags = 0; 181214455Srpaulo 182214455Srpaulo if (device == NULL) { 183214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 184214455Srpaulo "device is NULL: %s", pcap_strerror(errno)); 185214455Srpaulo return -1; 186214455Srpaulo } 187214455Srpaulo 188214455Srpaulo /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. 189214455Srpaulo * Since libpcap isn't thread-safe */ 190214455Srpaulo if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) 191214455Srpaulo flags |= SNF_F_PSHARED; 192214455Srpaulo else 193214455Srpaulo nr = NULL; 194214455Srpaulo 195214455Srpaulo err = snf_open(p->md.snf_boardnum, 196214455Srpaulo 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 197214455Srpaulo NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 198214455Srpaulo 0, /* default to SNF_DATARING_SIZE from env */ 199214455Srpaulo flags, /* may want pshared */ 200214455Srpaulo &p->md.snf_handle); 201214455Srpaulo if (err != 0) { 202214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 203214455Srpaulo "snf_open failed: %s", pcap_strerror(err)); 204214455Srpaulo return -1; 205214455Srpaulo } 206214455Srpaulo 207214455Srpaulo err = snf_ring_open(p->md.snf_handle, &p->md.snf_ring); 208214455Srpaulo if (err != 0) { 209214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 210214455Srpaulo "snf_ring_open failed: %s", pcap_strerror(err)); 211214455Srpaulo return -1; 212214455Srpaulo } 213214455Srpaulo 214214455Srpaulo if (p->md.timeout <= 0) 215214455Srpaulo p->md.snf_timeout = -1; 216214455Srpaulo else 217214455Srpaulo p->md.snf_timeout = p->md.timeout; 218214455Srpaulo 219214455Srpaulo err = snf_start(p->md.snf_handle); 220214455Srpaulo if (err != 0) { 221214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 222214455Srpaulo "snf_start failed: %s", pcap_strerror(err)); 223214455Srpaulo return -1; 224214455Srpaulo } 225214455Srpaulo 226214455Srpaulo /* 227214455Srpaulo * "select()" and "poll()" don't work on snf descriptors. 228214455Srpaulo */ 229214455Srpaulo p->selectable_fd = -1; 230214455Srpaulo p->linktype = DLT_EN10MB; 231214455Srpaulo p->read_op = snf_read; 232214455Srpaulo p->inject_op = snf_inject; 233214455Srpaulo p->setfilter_op = snf_setfilter; 234214455Srpaulo p->setdirection_op = NULL; /* Not implemented.*/ 235214455Srpaulo p->set_datalink_op = snf_set_datalink; 236214455Srpaulo p->getnonblock_op = snf_getnonblock; 237214455Srpaulo p->setnonblock_op = snf_setnonblock; 238214455Srpaulo p->stats_op = snf_pcap_stats; 239214455Srpaulo p->cleanup_op = snf_platform_cleanup; 240214455Srpaulo p->md.stat.ps_recv = 0; 241214455Srpaulo p->md.stat.ps_drop = 0; 242214455Srpaulo p->md.stat.ps_ifdrop = 0; 243214455Srpaulo return 0; 244214455Srpaulo} 245214455Srpaulo 246214455Srpauloint 247251129Sdelphijsnf_findalldevs(pcap_if_t **devlistp, char *errbuf) 248214455Srpaulo{ 249214455Srpaulo /* 250214455Srpaulo * There are no platform-specific devices since each device 251214455Srpaulo * exists as a regular Ethernet device. 252214455Srpaulo */ 253214455Srpaulo return 0; 254214455Srpaulo} 255214455Srpaulo 256214455Srpaulopcap_t * 257251129Sdelphijsnf_create(const char *device, char *ebuf, int *is_ours) 258214455Srpaulo{ 259214455Srpaulo pcap_t *p; 260214455Srpaulo int boardnum = -1; 261214455Srpaulo struct snf_ifaddrs *ifaddrs, *ifa; 262214455Srpaulo size_t devlen; 263214455Srpaulo 264251129Sdelphij if (snf_init(SNF_VERSION_API)) { 265251129Sdelphij /* Can't initialize the API, so no SNF devices */ 266251129Sdelphij *is_ours = 0; 267214455Srpaulo return NULL; 268251129Sdelphij } 269214455Srpaulo 270214455Srpaulo /* 271214455Srpaulo * Match a given interface name to our list of interface names, from 272214455Srpaulo * which we can obtain the intended board number 273214455Srpaulo */ 274251129Sdelphij if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { 275251129Sdelphij /* Can't get SNF addresses */ 276251129Sdelphij *is_ours = 0; 277214455Srpaulo return NULL; 278251129Sdelphij } 279214455Srpaulo devlen = strlen(device) + 1; 280214455Srpaulo ifa = ifaddrs; 281214455Srpaulo while (ifa) { 282214455Srpaulo if (!strncmp(device, ifa->snf_ifa_name, devlen)) { 283214455Srpaulo boardnum = ifa->snf_ifa_boardnum; 284214455Srpaulo break; 285214455Srpaulo } 286214455Srpaulo ifa = ifa->snf_ifa_next; 287214455Srpaulo } 288214455Srpaulo snf_freeifaddrs(ifaddrs); 289214455Srpaulo 290214455Srpaulo if (ifa == NULL) { 291214455Srpaulo /* 292214455Srpaulo * If we can't find the device by name, support the name "snfX" 293214455Srpaulo * and "snf10gX" where X is the board number. 294214455Srpaulo */ 295214455Srpaulo if (sscanf(device, "snf10g%d", &boardnum) != 1 && 296251129Sdelphij sscanf(device, "snf%d", &boardnum) != 1) { 297251129Sdelphij /* Nope, not a supported name */ 298251129Sdelphij *is_ours = 0; 299214455Srpaulo return NULL; 300251129Sdelphij } 301214455Srpaulo } 302214455Srpaulo 303251129Sdelphij /* OK, it's probably ours. */ 304251129Sdelphij *is_ours = 1; 305251129Sdelphij 306214455Srpaulo p = pcap_create_common(device, ebuf); 307214455Srpaulo if (p == NULL) 308214455Srpaulo return NULL; 309214455Srpaulo 310214455Srpaulo p->activate_op = snf_activate; 311214455Srpaulo p->md.snf_boardnum = boardnum; 312214455Srpaulo return p; 313214455Srpaulo} 314