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