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 #include "pcap-int.h" 20 21 static int 22 snf_set_datalink(pcap_t *p, int dlt) 23 { 24 p->linktype = dlt; 25 return (0); 26 } 27 28 static int 29 snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) 30 { 31 struct snf_ring_stats stats; 32 int rc; 33 34 if ((rc = snf_ring_getstats(p->md.snf_ring, &stats))) { 35 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", 36 pcap_strerror(rc)); 37 return -1; 38 } 39 ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; 40 ps->ps_drop = stats.ring_pkt_overflow; 41 ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; 42 return 0; 43 } 44 45 static void 46 snf_platform_cleanup(pcap_t *p) 47 { 48 if (p == NULL) 49 return; 50 51 snf_ring_close(p->md.snf_ring); 52 snf_close(p->md.snf_handle); 53 pcap_cleanup_live_common(p); 54 } 55 56 static int 57 snf_getnonblock(pcap_t *p, char *errbuf) 58 { 59 return (p->md.snf_timeout == 0); 60 } 61 62 static int 63 snf_setnonblock(pcap_t *p, int nonblock, char *errbuf) 64 { 65 if (nonblock) 66 p->md.snf_timeout = 0; 67 else { 68 if (p->md.timeout <= 0) 69 p->md.snf_timeout = -1; /* forever */ 70 else 71 p->md.snf_timeout = p->md.timeout; 72 } 73 return (0); 74 } 75 76 #define _NSEC_PER_SEC 1000000000 77 78 static inline 79 struct timeval 80 snf_timestamp_to_timeval(const int64_t ts_nanosec) 81 { 82 struct timeval tv; 83 int32_t rem; 84 if (ts_nanosec == 0) 85 return (struct timeval) { 0, 0 }; 86 tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; 87 tv.tv_usec = (ts_nanosec % _NSEC_PER_SEC) / 1000; 88 return tv; 89 } 90 91 static int 92 snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 93 { 94 struct pcap_pkthdr hdr; 95 int i, flags, err, caplen, n; 96 struct snf_recv_req req; 97 98 if (!p || cnt == 0) 99 return -1; 100 101 n = 0; 102 while (n < cnt || cnt < 0) { 103 /* 104 * Has "pcap_breakloop()" been called? 105 */ 106 if (p->break_loop) { 107 if (n == 0) { 108 p->break_loop = 0; 109 return (-2); 110 } else { 111 return (n); 112 } 113 } 114 115 err = snf_ring_recv(p->md.snf_ring, p->md.snf_timeout, &req); 116 117 if (err) { 118 if (err == EBUSY || err == EAGAIN) 119 return (0); 120 if (err == EINTR) 121 continue; 122 if (err != 0) { 123 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", 124 pcap_strerror(err)); 125 return -1; 126 } 127 } 128 129 caplen = req.length; 130 if (caplen > p->snapshot) 131 caplen = p->snapshot; 132 133 if ((p->fcode.bf_insns == NULL) || 134 bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 135 hdr.ts = snf_timestamp_to_timeval(req.timestamp); 136 hdr.caplen = caplen; 137 hdr.len = req.length; 138 callback(user, &hdr, req.pkt_addr); 139 } 140 n++; 141 } 142 return (n); 143 } 144 145 static int 146 snf_setfilter(pcap_t *p, struct bpf_program *fp) 147 { 148 if (!p) 149 return -1; 150 if (!fp) { 151 strncpy(p->errbuf, "setfilter: No filter specified", 152 sizeof(p->errbuf)); 153 return -1; 154 } 155 156 /* Make our private copy of the filter */ 157 158 if (install_bpf_program(p, fp) < 0) 159 return -1; 160 161 p->md.use_bpf = 0; 162 163 return (0); 164 } 165 166 static int 167 snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 168 { 169 strlcpy(p->errbuf, "Sending packets isn't supported with snf", 170 PCAP_ERRBUF_SIZE); 171 return (-1); 172 } 173 174 static int 175 snf_activate(pcap_t* p) 176 { 177 char *device = p->opt.source; 178 const char *nr = NULL; 179 int err; 180 int flags = 0; 181 182 if (device == NULL) { 183 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 184 "device is NULL: %s", pcap_strerror(errno)); 185 return -1; 186 } 187 188 /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. 189 * Since libpcap isn't thread-safe */ 190 if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) 191 flags |= SNF_F_PSHARED; 192 else 193 nr = NULL; 194 195 err = snf_open(p->md.snf_boardnum, 196 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 197 NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 198 0, /* default to SNF_DATARING_SIZE from env */ 199 flags, /* may want pshared */ 200 &p->md.snf_handle); 201 if (err != 0) { 202 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 203 "snf_open failed: %s", pcap_strerror(err)); 204 return -1; 205 } 206 207 err = snf_ring_open(p->md.snf_handle, &p->md.snf_ring); 208 if (err != 0) { 209 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 210 "snf_ring_open failed: %s", pcap_strerror(err)); 211 return -1; 212 } 213 214 if (p->md.timeout <= 0) 215 p->md.snf_timeout = -1; 216 else 217 p->md.snf_timeout = p->md.timeout; 218 219 err = snf_start(p->md.snf_handle); 220 if (err != 0) { 221 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 222 "snf_start failed: %s", pcap_strerror(err)); 223 return -1; 224 } 225 226 /* 227 * "select()" and "poll()" don't work on snf descriptors. 228 */ 229 p->selectable_fd = -1; 230 p->linktype = DLT_EN10MB; 231 p->read_op = snf_read; 232 p->inject_op = snf_inject; 233 p->setfilter_op = snf_setfilter; 234 p->setdirection_op = NULL; /* Not implemented.*/ 235 p->set_datalink_op = snf_set_datalink; 236 p->getnonblock_op = snf_getnonblock; 237 p->setnonblock_op = snf_setnonblock; 238 p->stats_op = snf_pcap_stats; 239 p->cleanup_op = snf_platform_cleanup; 240 p->md.stat.ps_recv = 0; 241 p->md.stat.ps_drop = 0; 242 p->md.stat.ps_ifdrop = 0; 243 return 0; 244 } 245 246 int 247 snf_findalldevs(pcap_if_t **devlistp, char *errbuf) 248 { 249 /* 250 * There are no platform-specific devices since each device 251 * exists as a regular Ethernet device. 252 */ 253 return 0; 254 } 255 256 pcap_t * 257 snf_create(const char *device, char *ebuf, int *is_ours) 258 { 259 pcap_t *p; 260 int boardnum = -1; 261 struct snf_ifaddrs *ifaddrs, *ifa; 262 size_t devlen; 263 264 if (snf_init(SNF_VERSION_API)) { 265 /* Can't initialize the API, so no SNF devices */ 266 *is_ours = 0; 267 return NULL; 268 } 269 270 /* 271 * Match a given interface name to our list of interface names, from 272 * which we can obtain the intended board number 273 */ 274 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { 275 /* Can't get SNF addresses */ 276 *is_ours = 0; 277 return NULL; 278 } 279 devlen = strlen(device) + 1; 280 ifa = ifaddrs; 281 while (ifa) { 282 if (!strncmp(device, ifa->snf_ifa_name, devlen)) { 283 boardnum = ifa->snf_ifa_boardnum; 284 break; 285 } 286 ifa = ifa->snf_ifa_next; 287 } 288 snf_freeifaddrs(ifaddrs); 289 290 if (ifa == NULL) { 291 /* 292 * If we can't find the device by name, support the name "snfX" 293 * and "snf10gX" where X is the board number. 294 */ 295 if (sscanf(device, "snf10g%d", &boardnum) != 1 && 296 sscanf(device, "snf%d", &boardnum) != 1) { 297 /* Nope, not a supported name */ 298 *is_ours = 0; 299 return NULL; 300 } 301 } 302 303 /* OK, it's probably ours. */ 304 *is_ours = 1; 305 306 p = pcap_create_common(device, ebuf); 307 if (p == NULL) 308 return NULL; 309 310 p->activate_op = snf_activate; 311 p->md.snf_boardnum = boardnum; 312 return p; 313 } 314