Home | History | Annotate | Line # | Download | only in dist
      1 /*	$NetBSD: pcap-nit.c,v 1.7 2024/09/02 15:33:37 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that: (1) source code distributions
      9  * retain the above copyright notice and this paragraph in its entirety, (2)
     10  * distributions including binary code include the above copyright notice and
     11  * this paragraph in its entirety in the documentation or other materials
     12  * provided with the distribution, and (3) all advertising materials mentioning
     13  * features or use of this software display the following acknowledgement:
     14  * ``This product includes software developed by the University of California,
     15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     16  * the University nor the names of its contributors may be used to endorse
     17  * or promote products derived from this software without specific prior
     18  * written permission.
     19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     22  */
     23 
     24 #include <sys/cdefs.h>
     25 __RCSID("$NetBSD: pcap-nit.c,v 1.7 2024/09/02 15:33:37 christos Exp $");
     26 
     27 #include <config.h>
     28 
     29 #include <sys/types.h>
     30 #include <sys/time.h>
     31 #include <sys/timeb.h>
     32 #include <sys/file.h>
     33 #include <sys/ioctl.h>
     34 #include <sys/socket.h>
     35 
     36 #include <net/if.h>
     37 #include <net/nit.h>
     38 
     39 #include <netinet/in.h>
     40 #include <netinet/in_systm.h>
     41 #include <netinet/ip.h>
     42 #include <netinet/if_ether.h>
     43 #include <netinet/ip_var.h>
     44 #include <netinet/udp.h>
     45 #include <netinet/udp_var.h>
     46 #include <netinet/tcp.h>
     47 #include <netinet/tcpip.h>
     48 
     49 #include <errno.h>
     50 #include <stdio.h>
     51 
     52 #include "pcap-int.h"
     53 
     54 #ifdef HAVE_OS_PROTO_H
     55 #include "os-proto.h"
     56 #endif
     57 
     58 /*
     59  * The chunk size for NIT.  This is the amount of buffering
     60  * done for read calls.
     61  */
     62 #define CHUNKSIZE (2*1024)
     63 
     64 /*
     65  * The total buffer space used by NIT.
     66  */
     67 #define BUFSPACE (4*CHUNKSIZE)
     68 
     69 /* Forwards */
     70 static int nit_setflags(int, int, int, char *);
     71 
     72 /*
     73  * Private data for capturing on NIT devices.
     74  */
     75 struct pcap_nit {
     76 	struct pcap_stat stat;
     77 };
     78 
     79 static int
     80 pcap_stats_nit(pcap_t *p, struct pcap_stat *ps)
     81 {
     82 	struct pcap_nit *pn = p->priv;
     83 
     84 	/*
     85 	 * "ps_recv" counts packets handed to the filter, not packets
     86 	 * that passed the filter.  As filtering is done in userland,
     87 	 * this does not include packets dropped because we ran out
     88 	 * of buffer space.
     89 	 *
     90 	 * "ps_drop" presumably counts packets dropped by the socket
     91 	 * because of flow control requirements or resource exhaustion;
     92 	 * it doesn't count packets dropped by the interface driver.
     93 	 * As filtering is done in userland, it counts packets regardless
     94 	 * of whether they would've passed the filter.
     95 	 *
     96 	 * These statistics don't include packets not yet read from the
     97 	 * kernel by libpcap or packets not yet read from libpcap by the
     98 	 * application.
     99 	 */
    100 	*ps = pn->stat;
    101 	return (0);
    102 }
    103 
    104 static int
    105 pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
    106 {
    107 	struct pcap_nit *pn = p->priv;
    108 	register int cc, n;
    109 	register u_char *bp, *cp, *ep;
    110 	register struct nit_hdr *nh;
    111 	register int caplen;
    112 
    113 	cc = p->cc;
    114 	if (cc == 0) {
    115 		cc = read(p->fd, (char *)p->buffer, p->bufsize);
    116 		if (cc < 0) {
    117 			if (errno == EWOULDBLOCK)
    118 				return (0);
    119 			pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
    120 			    errno, "pcap_read");
    121 			return (-1);
    122 		}
    123 		bp = (u_char *)p->buffer;
    124 	} else
    125 		bp = p->bp;
    126 
    127 	/*
    128 	 * Loop through each packet.  The increment expression
    129 	 * rounds up to the next int boundary past the end of
    130 	 * the previous packet.
    131 	 *
    132 	 * This assumes that a single buffer of packets will have
    133 	 * <= INT_MAX packets, so the packet count doesn't overflow.
    134 	 */
    135 	n = 0;
    136 	ep = bp + cc;
    137 	while (bp < ep) {
    138 		/*
    139 		 * Has "pcap_breakloop()" been called?
    140 		 * If so, return immediately - if we haven't read any
    141 		 * packets, clear the flag and return -2 to indicate
    142 		 * that we were told to break out of the loop, otherwise
    143 		 * leave the flag set, so that the *next* call will break
    144 		 * out of the loop without having read any packets, and
    145 		 * return the number of packets we've processed so far.
    146 		 */
    147 		if (p->break_loop) {
    148 			if (n == 0) {
    149 				p->break_loop = 0;
    150 				return (-2);
    151 			} else {
    152 				p->cc = ep - bp;
    153 				p->bp = bp;
    154 				return (n);
    155 			}
    156 		}
    157 
    158 		nh = (struct nit_hdr *)bp;
    159 		cp = bp + sizeof(*nh);
    160 
    161 		switch (nh->nh_state) {
    162 
    163 		case NIT_CATCH:
    164 			break;
    165 
    166 		case NIT_NOMBUF:
    167 		case NIT_NOCLUSTER:
    168 		case NIT_NOSPACE:
    169 			pn->stat.ps_drop = nh->nh_dropped;
    170 			continue;
    171 
    172 		case NIT_SEQNO:
    173 			continue;
    174 
    175 		default:
    176 			snprintf(p->errbuf, sizeof(p->errbuf),
    177 			    "bad nit state %d", nh->nh_state);
    178 			return (-1);
    179 		}
    180 		++pn->stat.ps_recv;
    181 		bp += ((sizeof(struct nit_hdr) + nh->nh_datalen +
    182 		    sizeof(int) - 1) & ~(sizeof(int) - 1));
    183 
    184 		caplen = nh->nh_wirelen;
    185 		if (caplen > p->snapshot)
    186 			caplen = p->snapshot;
    187 		if (pcapint_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) {
    188 			struct pcap_pkthdr h;
    189 			h.ts = nh->nh_timestamp;
    190 			h.len = nh->nh_wirelen;
    191 			h.caplen = caplen;
    192 			(*callback)(user, &h, cp);
    193 			if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
    194 				p->cc = ep - bp;
    195 				p->bp = bp;
    196 				return (n);
    197 			}
    198 		}
    199 	}
    200 	p->cc = 0;
    201 	return (n);
    202 }
    203 
    204 static int
    205 pcap_inject_nit(pcap_t *p, const void *buf, int size)
    206 {
    207 	struct sockaddr sa;
    208 	int ret;
    209 
    210 	memset(&sa, 0, sizeof(sa));
    211 	strncpy(sa.sa_data, device, sizeof(sa.sa_data));
    212 	ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa));
    213 	if (ret == -1) {
    214 		pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
    215 		    errno, "send");
    216 		return (-1);
    217 	}
    218 	return (ret);
    219 }
    220 
    221 static int
    222 nit_setflags(pcap_t *p)
    223 {
    224 	struct nit_ioc nioc;
    225 
    226 	memset(&nioc, 0, sizeof(nioc));
    227 	nioc.nioc_typetomatch = NT_ALLTYPES;
    228 	nioc.nioc_snaplen = p->snapshot;
    229 	nioc.nioc_bufalign = sizeof(int);
    230 	nioc.nioc_bufoffset = 0;
    231 
    232 	if (p->opt.buffer_size != 0)
    233 		nioc.nioc_bufspace = p->opt.buffer_size;
    234 	else {
    235 		/* Default buffer size */
    236 		nioc.nioc_bufspace = BUFSPACE;
    237 	}
    238 
    239 	if (p->opt.immediate) {
    240 		/*
    241 		 * XXX - will this cause packets to be delivered immediately?
    242 		 * XXX - given that this is for SunOS prior to 4.0, do
    243 		 * we care?
    244 		 */
    245 		nioc.nioc_chunksize = 0;
    246 	} else
    247 		nioc.nioc_chunksize = CHUNKSIZE;
    248 	if (p->opt.timeout != 0) {
    249 		nioc.nioc_flags |= NF_TIMEOUT;
    250 		nioc.nioc_timeout.tv_sec = p->opt.timeout / 1000;
    251 		nioc.nioc_timeout.tv_usec = (p->opt.timeout * 1000) % 1000000;
    252 	}
    253 	if (p->opt.promisc)
    254 		nioc.nioc_flags |= NF_PROMISC;
    255 
    256 	if (ioctl(p->fd, SIOCSNIT, &nioc) < 0) {
    257 		pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
    258 		    errno, "SIOCSNIT");
    259 		return (-1);
    260 	}
    261 	return (0);
    262 }
    263 
    264 static int
    265 pcap_activate_nit(pcap_t *p)
    266 {
    267 	int fd;
    268 	struct sockaddr_nit snit;
    269 
    270 	if (p->opt.rfmon) {
    271 		/*
    272 		 * No monitor mode on SunOS 3.x or earlier (no
    273 		 * Wi-Fi *devices* for the hardware that supported
    274 		 * them!).
    275 		 */
    276 		return (PCAP_ERROR_RFMON_NOTSUP);
    277 	}
    278 
    279 	/*
    280 	 * Turn a negative snapshot value (invalid), a snapshot value of
    281 	 * 0 (unspecified), or a value bigger than the normal maximum
    282 	 * value, into the maximum allowed value.
    283 	 *
    284 	 * If some application really *needs* a bigger snapshot
    285 	 * length, we should just increase MAXIMUM_SNAPLEN.
    286 	 */
    287 	if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
    288 		p->snapshot = MAXIMUM_SNAPLEN;
    289 
    290 	if (p->snapshot < 96)
    291 		/*
    292 		 * NIT requires a snapshot length of at least 96.
    293 		 */
    294 		p->snapshot = 96;
    295 
    296 	memset(p, 0, sizeof(*p));
    297 	p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
    298 	if (fd < 0) {
    299 		pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
    300 		    errno, "socket");
    301 		goto bad;
    302 	}
    303 	snit.snit_family = AF_NIT;
    304 	(void)strncpy(snit.snit_ifname, p->opt.device, NITIFSIZ);
    305 
    306 	if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
    307 		/*
    308 		 * XXX - there's probably a particular bind error that
    309 		 * means "there's no such device" and a particular bind
    310 		 * error that means "that device doesn't support NIT";
    311 		 * they might be the same error, if they both end up
    312 		 * meaning "NIT doesn't know about that device".
    313 		 */
    314 		pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
    315 		    errno, "bind: %s", snit.snit_ifname);
    316 		goto bad;
    317 	}
    318 	if (nit_setflags(p) < 0)
    319 		goto bad;
    320 
    321 	/*
    322 	 * NIT supports only ethernets.
    323 	 */
    324 	p->linktype = DLT_EN10MB;
    325 
    326 	p->bufsize = BUFSPACE;
    327 	p->buffer = malloc(p->bufsize);
    328 	if (p->buffer == NULL) {
    329 		pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
    330 		    errno, "malloc");
    331 		goto bad;
    332 	}
    333 
    334 	/*
    335 	 * "p->fd" is a socket, so "select()" should work on it.
    336 	 */
    337 	p->selectable_fd = p->fd;
    338 
    339 	/*
    340 	 * This is (presumably) a real Ethernet capture; give it a
    341 	 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
    342 	 * that an application can let you choose it, in case you're
    343 	 * capturing DOCSIS traffic that a Cisco Cable Modem
    344 	 * Termination System is putting out onto an Ethernet (it
    345 	 * doesn't put an Ethernet header onto the wire, it puts raw
    346 	 * DOCSIS frames out on the wire inside the low-level
    347 	 * Ethernet framing).
    348 	 */
    349 	p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
    350 	if (p->dlt_list == NULL) {
    351 		pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
    352 		    errno, "malloc");
    353 		goto bad;
    354 	}
    355 	p->dlt_list[0] = DLT_EN10MB;
    356 	p->dlt_list[1] = DLT_DOCSIS;
    357 	p->dlt_count = 2;
    358 
    359 	p->read_op = pcap_read_nit;
    360 	p->inject_op = pcap_inject_nit;
    361 	p->setfilter_op = pcapint_install_bpf_program;	/* no kernel filtering */
    362 	p->setdirection_op = NULL;	/* Not implemented. */
    363 	p->set_datalink_op = NULL;	/* can't change data link type */
    364 	p->getnonblock_op = pcapint_getnonblock_fd;
    365 	p->setnonblock_op = pcapint_setnonblock_fd;
    366 	p->stats_op = pcap_stats_nit;
    367 
    368 	return (0);
    369  bad:
    370 	pcapint_cleanup_live_common(p);
    371 	return (PCAP_ERROR);
    372 }
    373 
    374 pcap_t *
    375 pcapint_create_interface(const char *device _U_, char *ebuf)
    376 {
    377 	pcap_t *p;
    378 
    379 	p = PCAP_CREATE_COMMON(ebuf, struct pcap_nit);
    380 	if (p == NULL)
    381 		return (NULL);
    382 
    383 	p->activate_op = pcap_activate_nit;
    384 	return (p);
    385 }
    386 
    387 /*
    388  * XXX - there's probably a particular bind error that means "that device
    389  * doesn't support NIT"; if so, we should try a bind and use that.
    390  */
    391 static int
    392 can_be_bound(const char *name _U_)
    393 {
    394 	return (1);
    395 }
    396 
    397 static int
    398 get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_)
    399 {
    400 	/*
    401 	 * Nothing we can do.
    402 	 * XXX - is there a way to find out whether an adapter has
    403 	 * something plugged into it?
    404 	 */
    405 	return (0);
    406 }
    407 
    408 int
    409 pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
    410 {
    411 	return (pcapint_findalldevs_interfaces(devlistp, errbuf, can_be_bound,
    412 	    get_if_flags));
    413 }
    414 
    415 /*
    416  * Libpcap version string.
    417  */
    418 const char *
    419 pcap_lib_version(void)
    420 {
    421 	return (PCAP_VERSION_STRING);
    422 }
    423