1335640Shselasky/* 2335640Shselasky * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 3335640Shselasky * The Regents of the University of California. All rights reserved. 4335640Shselasky * 5335640Shselasky * Redistribution and use in source and binary forms, with or without 6335640Shselasky * modification, are permitted provided that: (1) source code distributions 7335640Shselasky * retain the above copyright notice and this paragraph in its entirety, (2) 8335640Shselasky * distributions including binary code include the above copyright notice and 9335640Shselasky * this paragraph in its entirety in the documentation or other materials 10335640Shselasky * provided with the distribution, and (3) all advertising materials mentioning 11335640Shselasky * features or use of this software display the following acknowledgement: 12335640Shselasky * ``This product includes software developed by the University of California, 13335640Shselasky * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14335640Shselasky * the University nor the names of its contributors may be used to endorse 15335640Shselasky * or promote products derived from this software without specific prior 16335640Shselasky * written permission. 17335640Shselasky * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18335640Shselasky * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19335640Shselasky * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20335640Shselasky */ 21335640Shselasky 22335640Shselasky#ifdef HAVE_CONFIG_H 23335640Shselasky#include <config.h> 24335640Shselasky#endif 25335640Shselasky 26335640Shselasky#include <sys/types.h> 27335640Shselasky#include <sys/time.h> 28335640Shselasky#include <sys/timeb.h> 29335640Shselasky#include <sys/file.h> 30335640Shselasky#include <sys/ioctl.h> 31335640Shselasky#include <sys/socket.h> 32335640Shselasky 33335640Shselasky#include <net/if.h> 34335640Shselasky#include <net/nit.h> 35335640Shselasky 36335640Shselasky#include <netinet/in.h> 37335640Shselasky#include <netinet/in_systm.h> 38335640Shselasky#include <netinet/ip.h> 39335640Shselasky#include <netinet/if_ether.h> 40335640Shselasky#include <netinet/ip_var.h> 41335640Shselasky#include <netinet/udp.h> 42335640Shselasky#include <netinet/udp_var.h> 43335640Shselasky#include <netinet/tcp.h> 44335640Shselasky#include <netinet/tcpip.h> 45335640Shselasky 46335640Shselasky#include <ctype.h> 47335640Shselasky#include <errno.h> 48335640Shselasky#include <stdio.h> 49335640Shselasky 50335640Shselasky#include "pcap-int.h" 51335640Shselasky 52335640Shselasky#ifdef HAVE_OS_PROTO_H 53335640Shselasky#include "os-proto.h" 54335640Shselasky#endif 55335640Shselasky 56335640Shselasky/* 57335640Shselasky * The chunk size for NIT. This is the amount of buffering 58335640Shselasky * done for read calls. 59335640Shselasky */ 60335640Shselasky#define CHUNKSIZE (2*1024) 61335640Shselasky 62335640Shselasky/* 63335640Shselasky * The total buffer space used by NIT. 64335640Shselasky */ 65335640Shselasky#define BUFSPACE (4*CHUNKSIZE) 66335640Shselasky 67335640Shselasky/* Forwards */ 68335640Shselaskystatic int nit_setflags(int, int, int, char *); 69335640Shselasky 70335640Shselasky/* 71335640Shselasky * Private data for capturing on NIT devices. 72335640Shselasky */ 73335640Shselaskystruct pcap_nit { 74335640Shselasky struct pcap_stat stat; 75335640Shselasky}; 76335640Shselasky 77335640Shselaskystatic int 78335640Shselaskypcap_stats_nit(pcap_t *p, struct pcap_stat *ps) 79335640Shselasky{ 80335640Shselasky struct pcap_nit *pn = p->priv; 81335640Shselasky 82335640Shselasky /* 83335640Shselasky * "ps_recv" counts packets handed to the filter, not packets 84335640Shselasky * that passed the filter. As filtering is done in userland, 85335640Shselasky * this does not include packets dropped because we ran out 86335640Shselasky * of buffer space. 87335640Shselasky * 88335640Shselasky * "ps_drop" presumably counts packets dropped by the socket 89335640Shselasky * because of flow control requirements or resource exhaustion; 90335640Shselasky * it doesn't count packets dropped by the interface driver. 91335640Shselasky * As filtering is done in userland, it counts packets regardless 92335640Shselasky * of whether they would've passed the filter. 93335640Shselasky * 94335640Shselasky * These statistics don't include packets not yet read from the 95335640Shselasky * kernel by libpcap or packets not yet read from libpcap by the 96335640Shselasky * application. 97335640Shselasky */ 98335640Shselasky *ps = pn->stat; 99335640Shselasky return (0); 100335640Shselasky} 101335640Shselasky 102335640Shselaskystatic int 103335640Shselaskypcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 104335640Shselasky{ 105335640Shselasky struct pcap_nit *pn = p->priv; 106335640Shselasky register int cc, n; 107335640Shselasky register u_char *bp, *cp, *ep; 108335640Shselasky register struct nit_hdr *nh; 109335640Shselasky register int caplen; 110335640Shselasky 111335640Shselasky cc = p->cc; 112335640Shselasky if (cc == 0) { 113335640Shselasky cc = read(p->fd, (char *)p->buffer, p->bufsize); 114335640Shselasky if (cc < 0) { 115335640Shselasky if (errno == EWOULDBLOCK) 116335640Shselasky return (0); 117335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), 118335640Shselasky errno, "pcap_read"); 119335640Shselasky return (-1); 120335640Shselasky } 121335640Shselasky bp = (u_char *)p->buffer; 122335640Shselasky } else 123335640Shselasky bp = p->bp; 124335640Shselasky 125335640Shselasky /* 126335640Shselasky * Loop through each packet. The increment expression 127335640Shselasky * rounds up to the next int boundary past the end of 128335640Shselasky * the previous packet. 129335640Shselasky */ 130335640Shselasky n = 0; 131335640Shselasky ep = bp + cc; 132335640Shselasky while (bp < ep) { 133335640Shselasky /* 134335640Shselasky * Has "pcap_breakloop()" been called? 135335640Shselasky * If so, return immediately - if we haven't read any 136335640Shselasky * packets, clear the flag and return -2 to indicate 137335640Shselasky * that we were told to break out of the loop, otherwise 138335640Shselasky * leave the flag set, so that the *next* call will break 139335640Shselasky * out of the loop without having read any packets, and 140335640Shselasky * return the number of packets we've processed so far. 141335640Shselasky */ 142335640Shselasky if (p->break_loop) { 143335640Shselasky if (n == 0) { 144335640Shselasky p->break_loop = 0; 145335640Shselasky return (-2); 146335640Shselasky } else { 147335640Shselasky p->cc = ep - bp; 148335640Shselasky p->bp = bp; 149335640Shselasky return (n); 150335640Shselasky } 151335640Shselasky } 152335640Shselasky 153335640Shselasky nh = (struct nit_hdr *)bp; 154335640Shselasky cp = bp + sizeof(*nh); 155335640Shselasky 156335640Shselasky switch (nh->nh_state) { 157335640Shselasky 158335640Shselasky case NIT_CATCH: 159335640Shselasky break; 160335640Shselasky 161335640Shselasky case NIT_NOMBUF: 162335640Shselasky case NIT_NOCLUSTER: 163335640Shselasky case NIT_NOSPACE: 164335640Shselasky pn->stat.ps_drop = nh->nh_dropped; 165335640Shselasky continue; 166335640Shselasky 167335640Shselasky case NIT_SEQNO: 168335640Shselasky continue; 169335640Shselasky 170335640Shselasky default: 171335640Shselasky pcap_snprintf(p->errbuf, sizeof(p->errbuf), 172335640Shselasky "bad nit state %d", nh->nh_state); 173335640Shselasky return (-1); 174335640Shselasky } 175335640Shselasky ++pn->stat.ps_recv; 176335640Shselasky bp += ((sizeof(struct nit_hdr) + nh->nh_datalen + 177335640Shselasky sizeof(int) - 1) & ~(sizeof(int) - 1)); 178335640Shselasky 179335640Shselasky caplen = nh->nh_wirelen; 180335640Shselasky if (caplen > p->snapshot) 181335640Shselasky caplen = p->snapshot; 182335640Shselasky if (bpf_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) { 183335640Shselasky struct pcap_pkthdr h; 184335640Shselasky h.ts = nh->nh_timestamp; 185335640Shselasky h.len = nh->nh_wirelen; 186335640Shselasky h.caplen = caplen; 187335640Shselasky (*callback)(user, &h, cp); 188335640Shselasky if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { 189335640Shselasky p->cc = ep - bp; 190335640Shselasky p->bp = bp; 191335640Shselasky return (n); 192335640Shselasky } 193335640Shselasky } 194335640Shselasky } 195335640Shselasky p->cc = 0; 196335640Shselasky return (n); 197335640Shselasky} 198335640Shselasky 199335640Shselaskystatic int 200335640Shselaskypcap_inject_nit(pcap_t *p, const void *buf, size_t size) 201335640Shselasky{ 202335640Shselasky struct sockaddr sa; 203335640Shselasky int ret; 204335640Shselasky 205335640Shselasky memset(&sa, 0, sizeof(sa)); 206335640Shselasky strncpy(sa.sa_data, device, sizeof(sa.sa_data)); 207335640Shselasky ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa)); 208335640Shselasky if (ret == -1) { 209335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 210335640Shselasky errno, "send"); 211335640Shselasky return (-1); 212335640Shselasky } 213335640Shselasky return (ret); 214335640Shselasky} 215335640Shselasky 216335640Shselaskystatic int 217335640Shselaskynit_setflags(pcap_t *p) 218335640Shselasky{ 219335640Shselasky struct nit_ioc nioc; 220335640Shselasky 221335640Shselasky memset(&nioc, 0, sizeof(nioc)); 222335640Shselasky nioc.nioc_typetomatch = NT_ALLTYPES; 223335640Shselasky nioc.nioc_snaplen = p->snapshot; 224335640Shselasky nioc.nioc_bufalign = sizeof(int); 225335640Shselasky nioc.nioc_bufoffset = 0; 226335640Shselasky 227335640Shselasky if (p->opt.buffer_size != 0) 228335640Shselasky nioc.nioc_bufspace = p->opt.buffer_size; 229335640Shselasky else { 230335640Shselasky /* Default buffer size */ 231335640Shselasky nioc.nioc_bufspace = BUFSPACE; 232335640Shselasky } 233335640Shselasky 234335640Shselasky if (p->opt.immediate) { 235335640Shselasky /* 236335640Shselasky * XXX - will this cause packets to be delivered immediately? 237335640Shselasky * XXX - given that this is for SunOS prior to 4.0, do 238335640Shselasky * we care? 239335640Shselasky */ 240335640Shselasky nioc.nioc_chunksize = 0; 241335640Shselasky } else 242335640Shselasky nioc.nioc_chunksize = CHUNKSIZE; 243335640Shselasky if (p->opt.timeout != 0) { 244335640Shselasky nioc.nioc_flags |= NF_TIMEOUT; 245335640Shselasky nioc.nioc_timeout.tv_sec = p->opt.timeout / 1000; 246335640Shselasky nioc.nioc_timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; 247335640Shselasky } 248335640Shselasky if (p->opt.promisc) 249335640Shselasky nioc.nioc_flags |= NF_PROMISC; 250335640Shselasky 251335640Shselasky if (ioctl(p->fd, SIOCSNIT, &nioc) < 0) { 252335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 253335640Shselasky errno, "SIOCSNIT"); 254335640Shselasky return (-1); 255335640Shselasky } 256335640Shselasky return (0); 257335640Shselasky} 258335640Shselasky 259335640Shselaskystatic int 260335640Shselaskypcap_activate_nit(pcap_t *p) 261335640Shselasky{ 262335640Shselasky int fd; 263335640Shselasky struct sockaddr_nit snit; 264335640Shselasky 265335640Shselasky if (p->opt.rfmon) { 266335640Shselasky /* 267335640Shselasky * No monitor mode on SunOS 3.x or earlier (no 268335640Shselasky * Wi-Fi *devices* for the hardware that supported 269335640Shselasky * them!). 270335640Shselasky */ 271335640Shselasky return (PCAP_ERROR_RFMON_NOTSUP); 272335640Shselasky } 273335640Shselasky 274335640Shselasky /* 275335640Shselasky * Turn a negative snapshot value (invalid), a snapshot value of 276335640Shselasky * 0 (unspecified), or a value bigger than the normal maximum 277335640Shselasky * value, into the maximum allowed value. 278335640Shselasky * 279335640Shselasky * If some application really *needs* a bigger snapshot 280335640Shselasky * length, we should just increase MAXIMUM_SNAPLEN. 281335640Shselasky */ 282335640Shselasky if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 283335640Shselasky p->snapshot = MAXIMUM_SNAPLEN; 284335640Shselasky 285335640Shselasky if (p->snapshot < 96) 286335640Shselasky /* 287335640Shselasky * NIT requires a snapshot length of at least 96. 288335640Shselasky */ 289335640Shselasky p->snapshot = 96; 290335640Shselasky 291335640Shselasky memset(p, 0, sizeof(*p)); 292335640Shselasky p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW); 293335640Shselasky if (fd < 0) { 294335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 295335640Shselasky errno, "socket"); 296335640Shselasky goto bad; 297335640Shselasky } 298335640Shselasky snit.snit_family = AF_NIT; 299335640Shselasky (void)strncpy(snit.snit_ifname, p->opt.device, NITIFSIZ); 300335640Shselasky 301335640Shselasky if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) { 302335640Shselasky /* 303335640Shselasky * XXX - there's probably a particular bind error that 304335640Shselasky * means "there's no such device" and a particular bind 305335640Shselasky * error that means "that device doesn't support NIT"; 306335640Shselasky * they might be the same error, if they both end up 307335640Shselasky * meaning "NIT doesn't know about that device". 308335640Shselasky */ 309335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 310335640Shselasky errno, "bind: %s", snit.snit_ifname); 311335640Shselasky goto bad; 312335640Shselasky } 313335640Shselasky if (nit_setflags(p) < 0) 314335640Shselasky goto bad; 315335640Shselasky 316335640Shselasky /* 317335640Shselasky * NIT supports only ethernets. 318335640Shselasky */ 319335640Shselasky p->linktype = DLT_EN10MB; 320335640Shselasky 321335640Shselasky p->bufsize = BUFSPACE; 322335640Shselasky p->buffer = malloc(p->bufsize); 323335640Shselasky if (p->buffer == NULL) { 324335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 325335640Shselasky errno, "malloc"); 326335640Shselasky goto bad; 327335640Shselasky } 328335640Shselasky 329335640Shselasky /* 330335640Shselasky * "p->fd" is a socket, so "select()" should work on it. 331335640Shselasky */ 332335640Shselasky p->selectable_fd = p->fd; 333335640Shselasky 334335640Shselasky /* 335335640Shselasky * This is (presumably) a real Ethernet capture; give it a 336335640Shselasky * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 337335640Shselasky * that an application can let you choose it, in case you're 338335640Shselasky * capturing DOCSIS traffic that a Cisco Cable Modem 339335640Shselasky * Termination System is putting out onto an Ethernet (it 340335640Shselasky * doesn't put an Ethernet header onto the wire, it puts raw 341335640Shselasky * DOCSIS frames out on the wire inside the low-level 342335640Shselasky * Ethernet framing). 343335640Shselasky */ 344335640Shselasky p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 345335640Shselasky /* 346335640Shselasky * If that fails, just leave the list empty. 347335640Shselasky */ 348335640Shselasky if (p->dlt_list != NULL) { 349335640Shselasky p->dlt_list[0] = DLT_EN10MB; 350335640Shselasky p->dlt_list[1] = DLT_DOCSIS; 351335640Shselasky p->dlt_count = 2; 352335640Shselasky } 353335640Shselasky 354335640Shselasky p->read_op = pcap_read_nit; 355335640Shselasky p->inject_op = pcap_inject_nit; 356335640Shselasky p->setfilter_op = install_bpf_program; /* no kernel filtering */ 357335640Shselasky p->setdirection_op = NULL; /* Not implemented. */ 358335640Shselasky p->set_datalink_op = NULL; /* can't change data link type */ 359335640Shselasky p->getnonblock_op = pcap_getnonblock_fd; 360335640Shselasky p->setnonblock_op = pcap_setnonblock_fd; 361335640Shselasky p->stats_op = pcap_stats_nit; 362335640Shselasky 363335640Shselasky return (0); 364335640Shselasky bad: 365335640Shselasky pcap_cleanup_live_common(p); 366335640Shselasky return (PCAP_ERROR); 367335640Shselasky} 368335640Shselasky 369335640Shselaskypcap_t * 370335640Shselaskypcap_create_interface(const char *device _U_, char *ebuf) 371335640Shselasky{ 372335640Shselasky pcap_t *p; 373335640Shselasky 374335640Shselasky p = pcap_create_common(ebuf, sizeof (struct pcap_nit)); 375335640Shselasky if (p == NULL) 376335640Shselasky return (NULL); 377335640Shselasky 378335640Shselasky p->activate_op = pcap_activate_nit; 379335640Shselasky return (p); 380335640Shselasky} 381335640Shselasky 382335640Shselasky/* 383335640Shselasky * XXX - there's probably a particular bind error that means "that device 384335640Shselasky * doesn't support NIT"; if so, we should try a bind and use that. 385335640Shselasky */ 386335640Shselaskystatic int 387335640Shselaskycan_be_bound(const char *name _U_) 388335640Shselasky{ 389335640Shselasky return (1); 390335640Shselasky} 391335640Shselasky 392335640Shselaskystatic int 393335640Shselaskyget_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) 394335640Shselasky{ 395335640Shselasky /* 396335640Shselasky * Nothing we can do. 397335640Shselasky * XXX - is there a way to find out whether an adapter has 398335640Shselasky * something plugged into it? 399335640Shselasky */ 400335640Shselasky return (0); 401335640Shselasky} 402335640Shselasky 403335640Shselaskyint 404335640Shselaskypcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 405335640Shselasky{ 406335640Shselasky return (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound, 407335640Shselasky get_if_flags)); 408335640Shselasky} 409335640Shselasky 410335640Shselasky/* 411335640Shselasky * Libpcap version string. 412335640Shselasky */ 413335640Shselaskyconst char * 414335640Shselaskypcap_lib_version(void) 415335640Shselasky{ 416335640Shselasky return (PCAP_VERSION_STRING); 417335640Shselasky} 418