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