pcap-nit.c revision 17683
1193323Sed/* 2193323Sed * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 3193323Sed * The Regents of the University of California. All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that: (1) source code distributions 7193323Sed * retain the above copyright notice and this paragraph in its entirety, (2) 8193323Sed * distributions including binary code include the above copyright notice and 9193323Sed * this paragraph in its entirety in the documentation or other materials 10193323Sed * provided with the distribution, and (3) all advertising materials mentioning 11193323Sed * features or use of this software display the following acknowledgement: 12193323Sed * ``This product includes software developed by the University of California, 13193323Sed * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14193323Sed * the University nor the names of its contributors may be used to endorse 15193323Sed * or promote products derived from this software without specific prior 16193323Sed * written permission. 17193323Sed * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18193323Sed * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19193323Sed * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20193323Sed */ 21193323Sed#ifndef lint 22198892Srdivackystatic char rcsid[] = 23198892Srdivacky "@(#)$Header: pcap-nit.c,v 1.29 96/07/15 00:48:51 leres Exp $ (LBL)"; 24198892Srdivacky#endif 25198090Srdivacky 26198090Srdivacky#include <sys/types.h> 27193323Sed#include <sys/time.h> 28193323Sed#include <sys/timeb.h> 29193323Sed#include <sys/file.h> 30193323Sed#include <sys/ioctl.h> 31193323Sed#include <sys/socket.h> 32198090Srdivacky 33193323Sed#include <net/if.h> 34193323Sed#include <net/nit.h> 35193323Sed 36193323Sed#include <netinet/in.h> 37198090Srdivacky#include <netinet/in_systm.h> 38193323Sed#include <netinet/ip.h> 39193323Sed#include <netinet/if_ether.h> 40193323Sed#include <netinet/ip_var.h> 41193323Sed#include <netinet/udp.h> 42198090Srdivacky#include <netinet/udp_var.h> 43198892Srdivacky#include <netinet/tcp.h> 44193323Sed#include <netinet/tcpip.h> 45198090Srdivacky 46198090Srdivacky#include <ctype.h> 47198892Srdivacky#include <errno.h> 48193323Sed#include <stdio.h> 49193323Sed 50198090Srdivacky#include "pcap-int.h" 51193323Sed 52193323Sed#include "gnuc.h" 53193323Sed#ifdef HAVE_OS_PROTO_H 54193323Sed#include "os-proto.h" 55198892Srdivacky#endif 56193323Sed 57198090Srdivacky/* 58198090Srdivacky * The chunk size for NIT. This is the amount of buffering 59198090Srdivacky * done for read calls. 60193323Sed */ 61198090Srdivacky#define CHUNKSIZE (2*1024) 62198090Srdivacky 63198090Srdivacky/* 64198892Srdivacky * The total buffer space used by NIT. 65193323Sed */ 66198892Srdivacky#define BUFSPACE (4*CHUNKSIZE) 67198892Srdivacky 68198892Srdivacky/* Forwards */ 69193323Sedstatic int nit_setflags(int, int, int, char *); 70193323Sed 71198090Srdivackyint 72193323Sedpcap_stats(pcap_t *p, struct pcap_stat *ps) 73193323Sed{ 74198090Srdivacky 75198090Srdivacky *ps = p->md.stat; 76198090Srdivacky return (0); 77198090Srdivacky} 78198090Srdivacky 79198090Srdivackyint 80198090Srdivackypcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 81198090Srdivacky{ 82198090Srdivacky register int cc, n; 83198090Srdivacky register struct bpf_insn *fcode = p->fcode.bf_insns; 84198892Srdivacky register u_char *bp, *cp, *ep; 85198892Srdivacky register struct nit_hdr *nh; 86193323Sed register int caplen; 87198892Srdivacky 88198090Srdivacky cc = p->cc; 89198396Srdivacky if (cc == 0) { 90198090Srdivacky cc = read(p->fd, (char *)p->buffer, p->bufsize); 91193323Sed if (cc < 0) { 92193323Sed if (errno == EWOULDBLOCK) 93198396Srdivacky return (0); 94198396Srdivacky sprintf(p->errbuf, "pcap_read: %s", 95193323Sed pcap_strerror(errno)); 96193323Sed return (-1); 97198090Srdivacky } 98198090Srdivacky bp = p->buffer; 99193323Sed } else 100193323Sed bp = p->bp; 101193323Sed 102193323Sed /* 103193323Sed * Loop through each packet. The increment expression 104193323Sed * rounds up to the next int boundary past the end of 105193323Sed * the previous packet. 106193323Sed */ 107193323Sed n = 0; 108193323Sed ep = bp + cc; 109193323Sed while (bp < ep) { 110193323Sed nh = (struct nit_hdr *)bp; 111193323Sed cp = bp + sizeof(*nh); 112193323Sed 113193323Sed switch (nh->nh_state) { 114198892Srdivacky 115193323Sed case NIT_CATCH: 116193323Sed break; 117193323Sed 118193323Sed case NIT_NOMBUF: 119193323Sed case NIT_NOCLUSTER: 120193323Sed case NIT_NOSPACE: 121193323Sed p->md.stat.ps_drop = nh->nh_dropped; 122193323Sed continue; 123193323Sed 124193323Sed case NIT_SEQNO: 125193323Sed continue; 126193323Sed 127193323Sed default: 128193323Sed sprintf(p->errbuf, "bad nit state %d", nh->nh_state); 129193323Sed return (-1); 130193323Sed } 131198892Srdivacky ++p->md.stat.ps_recv; 132198892Srdivacky bp += ((sizeof(struct nit_hdr) + nh->nh_datalen + 133198892Srdivacky sizeof(int) - 1) & ~(sizeof(int) - 1)); 134198090Srdivacky 135198090Srdivacky caplen = nh->nh_wirelen; 136198090Srdivacky if (caplen > p->snapshot) 137198090Srdivacky caplen = p->snapshot; 138198090Srdivacky if (bpf_filter(fcode, cp, nh->nh_wirelen, caplen)) { 139193323Sed struct pcap_pkthdr h; 140193323Sed h.ts = nh->nh_timestamp; 141193323Sed h.len = nh->nh_wirelen; 142193323Sed h.caplen = caplen; 143193323Sed (*callback)(user, &h, cp); 144193323Sed if (++n >= cnt && cnt >= 0) { 145198090Srdivacky p->cc = ep - bp; 146198892Srdivacky p->bp = bp; 147198892Srdivacky return (n); 148193323Sed } 149198892Srdivacky } 150193323Sed } 151193323Sed p->cc = 0; 152193323Sed return (n); 153193323Sed} 154193323Sed 155193323Sedstatic int 156193323Sednit_setflags(int fd, int promisc, int to_ms, char *ebuf) 157193323Sed{ 158193323Sed struct nit_ioc nioc; 159193323Sed 160193323Sed bzero((char *)&nioc, sizeof(nioc)); 161193323Sed nioc.nioc_bufspace = BUFSPACE; 162198090Srdivacky nioc.nioc_chunksize = CHUNKSIZE; 163193323Sed nioc.nioc_typetomatch = NT_ALLTYPES; 164193323Sed nioc.nioc_snaplen = p->snapshot; 165193323Sed nioc.nioc_bufalign = sizeof(int); 166193323Sed nioc.nioc_bufoffset = 0; 167193323Sed 168193323Sed if (to_ms != 0) { 169193323Sed nioc.nioc_flags |= NF_TIMEOUT; 170193323Sed nioc.nioc_timeout.tv_sec = to_ms / 1000; 171193323Sed nioc.nioc_timeout.tv_usec = (to_ms * 1000) % 1000000; 172198892Srdivacky } 173198892Srdivacky if (promisc) 174198892Srdivacky nioc.nioc_flags |= NF_PROMISC; 175198892Srdivacky 176198892Srdivacky if (ioctl(fd, SIOCSNIT, &nioc) < 0) { 177193323Sed sprintf(ebuf, "SIOCSNIT: %s", pcap_strerror(errno)); 178198892Srdivacky return (-1); 179198892Srdivacky } 180198892Srdivacky return (0); 181198892Srdivacky} 182198892Srdivacky 183198090Srdivackypcap_t * 184198090Srdivackypcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 185198090Srdivacky{ 186198090Srdivacky int fd; 187198090Srdivacky struct sockaddr_nit snit; 188198090Srdivacky register pcap_t *p; 189193323Sed 190193323Sed p = (pcap_t *)malloc(sizeof(*p)); 191193323Sed if (p == NULL) { 192193323Sed strcpy(ebuf, pcap_strerror(errno)); 193193323Sed return (NULL); 194193323Sed } 195193323Sed 196193323Sed if (snaplen < 96) 197193323Sed /* 198193323Sed * NIT requires a snapshot length of at least 96. 199193323Sed */ 200193323Sed snaplen = 96; 201193323Sed 202193323Sed bzero(p, sizeof(*p)); 203193323Sed p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW); 204193323Sed if (fd < 0) { 205193323Sed sprintf(ebuf, "socket: %s", pcap_strerror(errno)); 206193323Sed goto bad; 207193323Sed } 208193323Sed snit.snit_family = AF_NIT; 209193323Sed (void)strncpy(snit.snit_ifname, device, NITIFSIZ); 210193323Sed 211193323Sed if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) { 212193323Sed sprintf(ebuf, "bind: %s: %s", snit.snit_ifname, 213193323Sed pcap_strerror(errno)); 214193323Sed goto bad; 215198090Srdivacky } 216193323Sed p->snapshot = snaplen; 217198090Srdivacky nit_setflags(p->fd, promisc, to_ms, ebuf); 218198396Srdivacky 219199481Srdivacky /* 220198090Srdivacky * NIT supports only ethernets. 221198090Srdivacky */ 222198396Srdivacky p->linktype = DLT_EN10MB; 223198090Srdivacky 224198396Srdivacky p->bufsize = BUFSPACE; 225198090Srdivacky p->buffer = (u_char *)malloc(p->bufsize); 226199481Srdivacky if (p->buffer == NULL) { 227198396Srdivacky strcpy(ebuf, pcap_strerror(errno)); 228198090Srdivacky goto bad; 229198090Srdivacky } 230198396Srdivacky return (p); 231198396Srdivacky bad: 232198892Srdivacky if (fd >= 0) 233198892Srdivacky close(fd); 234198892Srdivacky free(p); 235198396Srdivacky return (NULL); 236198396Srdivacky} 237198090Srdivacky 238198090Srdivackyint 239193323Sedpcap_setfilter(pcap_t *p, struct bpf_program *fp) 240193323Sed{ 241198090Srdivacky 242193323Sed p->fcode = *fp; 243198090Srdivacky return (0); 244198090Srdivacky} 245198892Srdivacky