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