1 1.8 christos /* $NetBSD: pcap-snf.c,v 1.8 2024/09/02 15:33:37 christos Exp $ */ 2 1.8 christos 3 1.2 christos #include <sys/cdefs.h> 4 1.8 christos __RCSID("$NetBSD: pcap-snf.c,v 1.8 2024/09/02 15:33:37 christos Exp $"); 5 1.2 christos 6 1.5 christos #include <config.h> 7 1.1 christos 8 1.5 christos #ifndef _WIN32 9 1.1 christos #include <sys/param.h> 10 1.5 christos #endif /* !_WIN32 */ 11 1.1 christos 12 1.1 christos #include <stdlib.h> 13 1.1 christos #include <string.h> 14 1.1 christos #include <errno.h> 15 1.7 christos #include <limits.h> /* for INT_MAX */ 16 1.1 christos 17 1.5 christos #ifndef _WIN32 18 1.1 christos #include <netinet/in.h> 19 1.1 christos #include <sys/mman.h> 20 1.1 christos #include <sys/socket.h> 21 1.1 christos #include <sys/types.h> 22 1.1 christos #include <unistd.h> 23 1.5 christos #endif /* !_WIN32 */ 24 1.1 christos 25 1.2 christos #include <snf.h> 26 1.3 christos #if SNF_VERSION_API >= 0x0003 27 1.3 christos #define SNF_HAVE_INJECT_API 28 1.3 christos #endif 29 1.2 christos 30 1.1 christos #include "pcap-int.h" 31 1.2 christos #include "pcap-snf.h" 32 1.1 christos 33 1.2 christos /* 34 1.2 christos * Private data for capturing on SNF devices. 35 1.2 christos */ 36 1.2 christos struct pcap_snf { 37 1.2 christos snf_handle_t snf_handle; /* opaque device handle */ 38 1.2 christos snf_ring_t snf_ring; /* opaque device ring handle */ 39 1.3 christos #ifdef SNF_HAVE_INJECT_API 40 1.5 christos snf_inject_t snf_inj; /* inject handle, if inject is used */ 41 1.3 christos #endif 42 1.5 christos int snf_timeout; 43 1.5 christos int snf_boardnum; 44 1.2 christos }; 45 1.1 christos 46 1.1 christos static int 47 1.1 christos snf_set_datalink(pcap_t *p, int dlt) 48 1.1 christos { 49 1.1 christos p->linktype = dlt; 50 1.1 christos return (0); 51 1.1 christos } 52 1.1 christos 53 1.1 christos static int 54 1.1 christos snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) 55 1.1 christos { 56 1.1 christos struct snf_ring_stats stats; 57 1.3 christos struct pcap_snf *snfps = p->priv; 58 1.1 christos int rc; 59 1.1 christos 60 1.3 christos if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { 61 1.8 christos pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 62 1.5 christos rc, "snf_get_stats"); 63 1.1 christos return -1; 64 1.1 christos } 65 1.1 christos ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; 66 1.1 christos ps->ps_drop = stats.ring_pkt_overflow; 67 1.1 christos ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; 68 1.1 christos return 0; 69 1.1 christos } 70 1.1 christos 71 1.1 christos static void 72 1.1 christos snf_platform_cleanup(pcap_t *p) 73 1.1 christos { 74 1.2 christos struct pcap_snf *ps = p->priv; 75 1.2 christos 76 1.3 christos #ifdef SNF_HAVE_INJECT_API 77 1.5 christos if (ps->snf_inj) 78 1.5 christos snf_inject_close(ps->snf_inj); 79 1.3 christos #endif 80 1.2 christos snf_ring_close(ps->snf_ring); 81 1.2 christos snf_close(ps->snf_handle); 82 1.8 christos pcapint_cleanup_live_common(p); 83 1.1 christos } 84 1.1 christos 85 1.1 christos static int 86 1.5 christos snf_getnonblock(pcap_t *p) 87 1.1 christos { 88 1.2 christos struct pcap_snf *ps = p->priv; 89 1.2 christos 90 1.2 christos return (ps->snf_timeout == 0); 91 1.1 christos } 92 1.1 christos 93 1.1 christos static int 94 1.5 christos snf_setnonblock(pcap_t *p, int nonblock) 95 1.1 christos { 96 1.2 christos struct pcap_snf *ps = p->priv; 97 1.2 christos 98 1.1 christos if (nonblock) 99 1.2 christos ps->snf_timeout = 0; 100 1.1 christos else { 101 1.2 christos if (p->opt.timeout <= 0) 102 1.2 christos ps->snf_timeout = -1; /* forever */ 103 1.1 christos else 104 1.2 christos ps->snf_timeout = p->opt.timeout; 105 1.1 christos } 106 1.1 christos return (0); 107 1.1 christos } 108 1.1 christos 109 1.1 christos #define _NSEC_PER_SEC 1000000000 110 1.1 christos 111 1.1 christos static inline 112 1.1 christos struct timeval 113 1.3 christos snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) 114 1.1 christos { 115 1.1 christos struct timeval tv; 116 1.3 christos long tv_nsec; 117 1.5 christos const static struct timeval zero_timeval; 118 1.3 christos 119 1.5 christos if (ts_nanosec == 0) 120 1.5 christos return zero_timeval; 121 1.3 christos 122 1.1 christos tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; 123 1.3 christos tv_nsec = (ts_nanosec % _NSEC_PER_SEC); 124 1.3 christos 125 1.3 christos /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ 126 1.3 christos if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) 127 1.3 christos tv.tv_usec = tv_nsec; 128 1.3 christos else 129 1.3 christos tv.tv_usec = tv_nsec / 1000; 130 1.3 christos 131 1.1 christos return tv; 132 1.1 christos } 133 1.1 christos 134 1.1 christos static int 135 1.1 christos snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 136 1.1 christos { 137 1.2 christos struct pcap_snf *ps = p->priv; 138 1.1 christos struct pcap_pkthdr hdr; 139 1.1 christos int i, flags, err, caplen, n; 140 1.1 christos struct snf_recv_req req; 141 1.3 christos int nonblock, timeout; 142 1.1 christos 143 1.3 christos if (!p) 144 1.1 christos return -1; 145 1.1 christos 146 1.7 christos /* 147 1.7 christos * This can conceivably process more than INT_MAX packets, 148 1.7 christos * which would overflow the packet count, causing it either 149 1.7 christos * to look like a negative number, and thus cause us to 150 1.7 christos * return a value that looks like an error, or overflow 151 1.7 christos * back into positive territory, and thus cause us to 152 1.7 christos * return a too-low count. 153 1.7 christos * 154 1.7 christos * Therefore, if the packet count is unlimited, we clip 155 1.7 christos * it at INT_MAX; this routine is not expected to 156 1.7 christos * process packets indefinitely, so that's not an issue. 157 1.7 christos */ 158 1.7 christos if (PACKET_COUNT_IS_UNLIMITED(cnt)) 159 1.7 christos cnt = INT_MAX; 160 1.7 christos 161 1.1 christos n = 0; 162 1.3 christos timeout = ps->snf_timeout; 163 1.7 christos while (n < cnt) { 164 1.1 christos /* 165 1.1 christos * Has "pcap_breakloop()" been called? 166 1.1 christos */ 167 1.1 christos if (p->break_loop) { 168 1.1 christos if (n == 0) { 169 1.1 christos p->break_loop = 0; 170 1.1 christos return (-2); 171 1.1 christos } else { 172 1.1 christos return (n); 173 1.1 christos } 174 1.1 christos } 175 1.1 christos 176 1.3 christos err = snf_ring_recv(ps->snf_ring, timeout, &req); 177 1.1 christos 178 1.1 christos if (err) { 179 1.3 christos if (err == EBUSY || err == EAGAIN) { 180 1.3 christos return (n); 181 1.3 christos } 182 1.3 christos else if (err == EINTR) { 183 1.3 christos timeout = 0; 184 1.1 christos continue; 185 1.3 christos } 186 1.3 christos else { 187 1.8 christos pcapint_fmt_errmsg_for_errno(p->errbuf, 188 1.5 christos PCAP_ERRBUF_SIZE, err, "snf_read"); 189 1.1 christos return -1; 190 1.1 christos } 191 1.1 christos } 192 1.1 christos 193 1.1 christos caplen = req.length; 194 1.1 christos if (caplen > p->snapshot) 195 1.1 christos caplen = p->snapshot; 196 1.1 christos 197 1.1 christos if ((p->fcode.bf_insns == NULL) || 198 1.8 christos pcapint_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 199 1.3 christos hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); 200 1.1 christos hdr.caplen = caplen; 201 1.1 christos hdr.len = req.length; 202 1.1 christos callback(user, &hdr, req.pkt_addr); 203 1.6 christos n++; 204 1.1 christos } 205 1.3 christos 206 1.3 christos /* After one successful packet is received, we won't block 207 1.3 christos * again for that timeout. */ 208 1.3 christos if (timeout != 0) 209 1.3 christos timeout = 0; 210 1.1 christos } 211 1.1 christos return (n); 212 1.1 christos } 213 1.1 christos 214 1.1 christos static int 215 1.7 christos snf_inject(pcap_t *p, const void *buf _U_, int size _U_) 216 1.1 christos { 217 1.3 christos #ifdef SNF_HAVE_INJECT_API 218 1.3 christos struct pcap_snf *ps = p->priv; 219 1.5 christos int rc; 220 1.5 christos if (ps->snf_inj == NULL) { 221 1.5 christos rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); 222 1.5 christos if (rc) { 223 1.8 christos pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 224 1.5 christos rc, "snf_inject_open"); 225 1.5 christos return (-1); 226 1.5 christos } 227 1.5 christos } 228 1.5 christos 229 1.5 christos rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); 230 1.5 christos if (!rc) { 231 1.5 christos return (size); 232 1.5 christos } 233 1.5 christos else { 234 1.8 christos pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 235 1.5 christos rc, "snf_inject_send"); 236 1.5 christos return (-1); 237 1.5 christos } 238 1.3 christos #else 239 1.8 christos pcapint_strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", 240 1.1 christos PCAP_ERRBUF_SIZE); 241 1.1 christos return (-1); 242 1.3 christos #endif 243 1.1 christos } 244 1.1 christos 245 1.1 christos static int 246 1.1 christos snf_activate(pcap_t* p) 247 1.1 christos { 248 1.2 christos struct pcap_snf *ps = p->priv; 249 1.4 christos char *device = p->opt.device; 250 1.1 christos const char *nr = NULL; 251 1.1 christos int err; 252 1.3 christos int flags = -1, ring_id = -1; 253 1.1 christos 254 1.1 christos if (device == NULL) { 255 1.7 christos snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); 256 1.1 christos return -1; 257 1.1 christos } 258 1.1 christos 259 1.1 christos /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. 260 1.1 christos * Since libpcap isn't thread-safe */ 261 1.3 christos if ((nr = getenv("SNF_FLAGS")) && *nr) 262 1.3 christos flags = strtol(nr, NULL, 0); 263 1.3 christos else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) 264 1.3 christos flags = SNF_F_PSHARED; 265 1.1 christos else 266 1.1 christos nr = NULL; 267 1.1 christos 268 1.5 christos 269 1.5 christos /* Allow pcap_set_buffer_size() to set dataring_size. 270 1.5 christos * Default is zero which allows setting from env SNF_DATARING_SIZE. 271 1.5 christos * pcap_set_buffer_size() is in bytes while snf_open() accepts values 272 1.5 christos * between 0 and 1048576 in Megabytes. Values in this range are 273 1.5 christos * mapped to 1MB. 274 1.5 christos */ 275 1.2 christos err = snf_open(ps->snf_boardnum, 276 1.1 christos 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 277 1.1 christos NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 278 1.5 christos (p->opt.buffer_size > 0 && p->opt.buffer_size < 1048576) ? 1048576 : p->opt.buffer_size, /* default to SNF_DATARING_SIZE from env */ 279 1.1 christos flags, /* may want pshared */ 280 1.2 christos &ps->snf_handle); 281 1.1 christos if (err != 0) { 282 1.8 christos pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 283 1.5 christos err, "snf_open failed"); 284 1.1 christos return -1; 285 1.1 christos } 286 1.1 christos 287 1.3 christos if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { 288 1.3 christos ring_id = (int) strtol(nr, NULL, 0); 289 1.3 christos } 290 1.3 christos err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); 291 1.1 christos if (err != 0) { 292 1.8 christos pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 293 1.5 christos err, "snf_ring_open_id(ring=%d) failed", ring_id); 294 1.1 christos return -1; 295 1.1 christos } 296 1.1 christos 297 1.5 christos /* 298 1.5 christos * Turn a negative snapshot value (invalid), a snapshot value of 299 1.5 christos * 0 (unspecified), or a value bigger than the normal maximum 300 1.5 christos * value, into the maximum allowed value. 301 1.5 christos * 302 1.5 christos * If some application really *needs* a bigger snapshot 303 1.5 christos * length, we should just increase MAXIMUM_SNAPLEN. 304 1.5 christos */ 305 1.5 christos if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 306 1.5 christos p->snapshot = MAXIMUM_SNAPLEN; 307 1.5 christos 308 1.2 christos if (p->opt.timeout <= 0) 309 1.2 christos ps->snf_timeout = -1; 310 1.1 christos else 311 1.2 christos ps->snf_timeout = p->opt.timeout; 312 1.1 christos 313 1.2 christos err = snf_start(ps->snf_handle); 314 1.1 christos if (err != 0) { 315 1.8 christos pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 316 1.5 christos err, "snf_start failed"); 317 1.1 christos return -1; 318 1.1 christos } 319 1.1 christos 320 1.1 christos /* 321 1.1 christos * "select()" and "poll()" don't work on snf descriptors. 322 1.1 christos */ 323 1.5 christos #ifndef _WIN32 324 1.1 christos p->selectable_fd = -1; 325 1.5 christos #endif /* !_WIN32 */ 326 1.1 christos p->linktype = DLT_EN10MB; 327 1.1 christos p->read_op = snf_read; 328 1.1 christos p->inject_op = snf_inject; 329 1.8 christos p->setfilter_op = pcapint_install_bpf_program; 330 1.1 christos p->setdirection_op = NULL; /* Not implemented.*/ 331 1.1 christos p->set_datalink_op = snf_set_datalink; 332 1.1 christos p->getnonblock_op = snf_getnonblock; 333 1.1 christos p->setnonblock_op = snf_setnonblock; 334 1.1 christos p->stats_op = snf_pcap_stats; 335 1.1 christos p->cleanup_op = snf_platform_cleanup; 336 1.3 christos #ifdef SNF_HAVE_INJECT_API 337 1.5 christos ps->snf_inj = NULL; 338 1.3 christos #endif 339 1.1 christos return 0; 340 1.1 christos } 341 1.1 christos 342 1.3 christos #define MAX_DESC_LENGTH 128 343 1.1 christos int 344 1.5 christos snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf) 345 1.1 christos { 346 1.5 christos pcap_if_t *dev; 347 1.5 christos #ifdef _WIN32 348 1.5 christos struct sockaddr_in addr; 349 1.5 christos #endif 350 1.3 christos struct snf_ifaddrs *ifaddrs, *ifa; 351 1.5 christos char name[MAX_DESC_LENGTH]; 352 1.3 christos char desc[MAX_DESC_LENGTH]; 353 1.5 christos int ret, allports = 0, merge = 0; 354 1.5 christos const char *nr = NULL; 355 1.3 christos 356 1.5 christos if (snf_init(SNF_VERSION_API)) { 357 1.7 christos (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 358 1.5 christos "snf_getifaddrs: snf_init failed"); 359 1.3 christos return (-1); 360 1.5 christos } 361 1.3 christos 362 1.3 christos if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) 363 1.3 christos { 364 1.8 christos pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 365 1.5 christos errno, "snf_getifaddrs"); 366 1.3 christos return (-1); 367 1.3 christos } 368 1.5 christos if ((nr = getenv("SNF_FLAGS")) && *nr) { 369 1.5 christos errno = 0; 370 1.5 christos merge = strtol(nr, NULL, 0); 371 1.5 christos if (errno) { 372 1.7 christos (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 373 1.5 christos "snf_getifaddrs: SNF_FLAGS is not a valid number"); 374 1.5 christos return (-1); 375 1.5 christos } 376 1.5 christos merge = merge & SNF_F_AGGREGATE_PORTMASK; 377 1.5 christos } 378 1.5 christos 379 1.5 christos for (ifa = ifaddrs; ifa != NULL; ifa = ifa->snf_ifa_next) { 380 1.5 christos /* 381 1.5 christos * Myricom SNF adapter ports may appear as regular 382 1.5 christos * network interfaces, which would already have been 383 1.8 christos * added to the list of adapters by pcapint_platform_finddevs() 384 1.5 christos * if this isn't an SNF-only version of libpcap. 385 1.5 christos * 386 1.5 christos * Our create routine intercepts pcap_create() calls for 387 1.5 christos * those interfaces and arranges that they will be 388 1.5 christos * opened using the SNF API instead. 389 1.5 christos * 390 1.5 christos * So if we already have an entry for the device, we 391 1.5 christos * don't add an additional entry for it, we just 392 1.5 christos * update the description for it, if any, to indicate 393 1.5 christos * which snfN device it is. Otherwise, we add an entry 394 1.5 christos * for it. 395 1.5 christos * 396 1.5 christos * In either case, if SNF_F_AGGREGATE_PORTMASK is set 397 1.5 christos * in SNF_FLAGS, we add this port to the bitmask 398 1.5 christos * of ports, which we use to generate a device 399 1.5 christos * we can use to capture on all ports. 400 1.5 christos * 401 1.5 christos * Generate the description string. If port aggregation 402 1.5 christos * is set, use 2^{port number} as the unit number, 403 1.5 christos * rather than {port number}. 404 1.5 christos * 405 1.5 christos * XXX - do entries in this list have IP addresses for 406 1.5 christos * the port? If so, should we add them to the 407 1.5 christos * entry for the device, if they're not already in the 408 1.5 christos * list of IP addresses for the device? 409 1.7 christos */ 410 1.7 christos (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d", 411 1.5 christos merge ? "Merge Bitmask Port " : "", 412 1.5 christos merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum); 413 1.5 christos /* 414 1.5 christos * Add the port to the bitmask. 415 1.5 christos */ 416 1.5 christos if (merge) 417 1.5 christos allports |= 1 << ifa->snf_ifa_portnum; 418 1.3 christos /* 419 1.5 christos * See if there's already an entry for the device 420 1.5 christos * with the name ifa->snf_ifa_name. 421 1.3 christos */ 422 1.8 christos dev = pcapint_find_dev(devlistp, ifa->snf_ifa_name); 423 1.5 christos if (dev != NULL) { 424 1.5 christos /* 425 1.5 christos * Yes. Update its description. 426 1.5 christos */ 427 1.5 christos char *desc_str; 428 1.5 christos 429 1.5 christos desc_str = strdup(desc); 430 1.5 christos if (desc_str == NULL) { 431 1.8 christos pcapint_fmt_errmsg_for_errno(errbuf, 432 1.5 christos PCAP_ERRBUF_SIZE, errno, 433 1.5 christos "snf_findalldevs strdup"); 434 1.5 christos return -1; 435 1.5 christos } 436 1.5 christos free(dev->description); 437 1.5 christos dev->description = desc_str; 438 1.5 christos } else { 439 1.5 christos /* 440 1.5 christos * No. Add an entry for it. 441 1.5 christos * 442 1.5 christos * XXX - is there a notion of "up" or "running", 443 1.5 christos * and can we determine whether something's 444 1.5 christos * plugged into the adapter and set 445 1.5 christos * PCAP_IF_CONNECTION_STATUS_CONNECTED or 446 1.5 christos * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? 447 1.5 christos */ 448 1.8 christos dev = pcapint_add_dev(devlistp, ifa->snf_ifa_name, 0, desc, 449 1.5 christos errbuf); 450 1.5 christos if (dev == NULL) 451 1.5 christos return -1; 452 1.5 christos #ifdef _WIN32 453 1.5 christos /* 454 1.5 christos * On Windows, fill in IP# from device name 455 1.5 christos */ 456 1.5 christos ret = inet_pton(AF_INET, dev->name, &addr.sin_addr); 457 1.5 christos if (ret == 1) { 458 1.7 christos /* 459 1.7 christos * Successful conversion of device name 460 1.7 christos * to IPv4 address. 461 1.7 christos */ 462 1.7 christos addr.sin_family = AF_INET; 463 1.8 christos if (pcapint_add_addr_to_dev(dev, &addr, sizeof(addr), 464 1.7 christos NULL, 0, NULL, 0, NULL, 0, errbuf) == -1) 465 1.7 christos return -1; 466 1.5 christos } else if (ret == -1) { 467 1.5 christos /* 468 1.5 christos * Error. 469 1.5 christos */ 470 1.8 christos pcapint_fmt_errmsg_for_errno(errbuf, 471 1.5 christos PCAP_ERRBUF_SIZE, errno, 472 1.5 christos "sinf_findalldevs inet_pton"); 473 1.5 christos return -1; 474 1.5 christos } 475 1.5 christos #endif _WIN32 476 1.3 christos } 477 1.5 christos } 478 1.5 christos snf_freeifaddrs(ifaddrs); 479 1.5 christos /* 480 1.5 christos * Create a snfX entry if port aggregation is enabled 481 1.7 christos */ 482 1.5 christos if (merge) { 483 1.5 christos /* 484 1.5 christos * Add a new entry with all ports bitmask 485 1.5 christos */ 486 1.7 christos (void)snprintf(name,MAX_DESC_LENGTH,"snf%d",allports); 487 1.7 christos (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d", 488 1.5 christos allports); 489 1.3 christos /* 490 1.5 christos * XXX - is there any notion of "up" and "running" that 491 1.5 christos * would apply to this device, given that it handles 492 1.5 christos * multiple ports? 493 1.5 christos * 494 1.5 christos * Presumably, there's no notion of "connected" vs. 495 1.5 christos * "disconnected", as "is this plugged into a network?" 496 1.5 christos * would be a per-port property. 497 1.3 christos */ 498 1.8 christos if (pcapint_add_dev(devlistp, name, 499 1.5 christos PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc, 500 1.5 christos errbuf) == NULL) 501 1.3 christos return (-1); 502 1.5 christos /* 503 1.5 christos * XXX - should we give it a list of addresses with all 504 1.5 christos * the addresses for all the ports? 505 1.5 christos */ 506 1.3 christos } 507 1.3 christos 508 1.1 christos return 0; 509 1.1 christos } 510 1.1 christos 511 1.1 christos pcap_t * 512 1.2 christos snf_create(const char *device, char *ebuf, int *is_ours) 513 1.1 christos { 514 1.1 christos pcap_t *p; 515 1.1 christos int boardnum = -1; 516 1.1 christos struct snf_ifaddrs *ifaddrs, *ifa; 517 1.1 christos size_t devlen; 518 1.2 christos struct pcap_snf *ps; 519 1.1 christos 520 1.2 christos if (snf_init(SNF_VERSION_API)) { 521 1.2 christos /* Can't initialize the API, so no SNF devices */ 522 1.2 christos *is_ours = 0; 523 1.1 christos return NULL; 524 1.2 christos } 525 1.1 christos 526 1.1 christos /* 527 1.1 christos * Match a given interface name to our list of interface names, from 528 1.1 christos * which we can obtain the intended board number 529 1.1 christos */ 530 1.2 christos if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { 531 1.2 christos /* Can't get SNF addresses */ 532 1.2 christos *is_ours = 0; 533 1.1 christos return NULL; 534 1.2 christos } 535 1.1 christos devlen = strlen(device) + 1; 536 1.1 christos ifa = ifaddrs; 537 1.1 christos while (ifa) { 538 1.5 christos if (strncmp(device, ifa->snf_ifa_name, devlen) == 0) { 539 1.1 christos boardnum = ifa->snf_ifa_boardnum; 540 1.1 christos break; 541 1.1 christos } 542 1.1 christos ifa = ifa->snf_ifa_next; 543 1.1 christos } 544 1.1 christos snf_freeifaddrs(ifaddrs); 545 1.1 christos 546 1.1 christos if (ifa == NULL) { 547 1.1 christos /* 548 1.1 christos * If we can't find the device by name, support the name "snfX" 549 1.1 christos * and "snf10gX" where X is the board number. 550 1.1 christos */ 551 1.1 christos if (sscanf(device, "snf10g%d", &boardnum) != 1 && 552 1.2 christos sscanf(device, "snf%d", &boardnum) != 1) { 553 1.2 christos /* Nope, not a supported name */ 554 1.2 christos *is_ours = 0; 555 1.1 christos return NULL; 556 1.5 christos } 557 1.1 christos } 558 1.1 christos 559 1.2 christos /* OK, it's probably ours. */ 560 1.2 christos *is_ours = 1; 561 1.2 christos 562 1.7 christos p = PCAP_CREATE_COMMON(ebuf, struct pcap_snf); 563 1.1 christos if (p == NULL) 564 1.1 christos return NULL; 565 1.2 christos ps = p->priv; 566 1.1 christos 567 1.3 christos /* 568 1.3 christos * We support microsecond and nanosecond time stamps. 569 1.3 christos */ 570 1.3 christos p->tstamp_precision_list = malloc(2 * sizeof(u_int)); 571 1.3 christos if (p->tstamp_precision_list == NULL) { 572 1.8 christos pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, 573 1.5 christos "malloc"); 574 1.4 christos pcap_close(p); 575 1.3 christos return NULL; 576 1.3 christos } 577 1.3 christos p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; 578 1.3 christos p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; 579 1.7 christos p->tstamp_precision_count = 2; 580 1.3 christos 581 1.1 christos p->activate_op = snf_activate; 582 1.2 christos ps->snf_boardnum = boardnum; 583 1.1 christos return p; 584 1.1 christos } 585 1.4 christos 586 1.4 christos #ifdef SNF_ONLY 587 1.4 christos /* 588 1.4 christos * This libpcap build supports only SNF cards, not regular network 589 1.4 christos * interfaces.. 590 1.4 christos */ 591 1.4 christos 592 1.4 christos /* 593 1.5 christos * There are no regular interfaces, just SNF interfaces. 594 1.4 christos */ 595 1.4 christos int 596 1.8 christos pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 597 1.4 christos { 598 1.4 christos return (0); 599 1.4 christos } 600 1.4 christos 601 1.4 christos /* 602 1.4 christos * Attempts to open a regular interface fail. 603 1.4 christos */ 604 1.4 christos pcap_t * 605 1.8 christos pcapint_create_interface(const char *device, char *errbuf) 606 1.4 christos { 607 1.7 christos snprintf(errbuf, PCAP_ERRBUF_SIZE, 608 1.4 christos "This version of libpcap only supports SNF cards"); 609 1.4 christos return NULL; 610 1.4 christos } 611 1.5 christos 612 1.5 christos /* 613 1.5 christos * Libpcap version string. 614 1.5 christos */ 615 1.5 christos const char * 616 1.5 christos pcap_lib_version(void) 617 1.5 christos { 618 1.5 christos return (PCAP_VERSION_STRING " (SNF-only)"); 619 1.5 christos } 620 1.4 christos #endif 621