PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/external/bsd/libpcap/dist/pcap-nit.c

https://gitlab.com/storedmirrors/minix
C | 372 lines | 230 code | 47 blank | 95 comment | 36 complexity | d87456feec18e8b9db2a717f2e08ba0b MD5 | raw file
  1. /* $NetBSD: pcap-nit.c,v 1.3 2015/03/31 21:39:42 christos Exp $ */
  2. /*
  3. * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that: (1) source code distributions
  8. * retain the above copyright notice and this paragraph in its entirety, (2)
  9. * distributions including binary code include the above copyright notice and
  10. * this paragraph in its entirety in the documentation or other materials
  11. * provided with the distribution, and (3) all advertising materials mentioning
  12. * features or use of this software display the following acknowledgement:
  13. * ``This product includes software developed by the University of California,
  14. * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  15. * the University nor the names of its contributors may be used to endorse
  16. * or promote products derived from this software without specific prior
  17. * written permission.
  18. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  19. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  20. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  21. */
  22. #include <sys/cdefs.h>
  23. __RCSID("$NetBSD: pcap-nit.c,v 1.3 2015/03/31 21:39:42 christos Exp $");
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #include <sys/types.h>
  28. #include <sys/time.h>
  29. #include <sys/timeb.h>
  30. #include <sys/file.h>
  31. #include <sys/ioctl.h>
  32. #include <sys/socket.h>
  33. #include <net/if.h>
  34. #include <net/nit.h>
  35. #include <netinet/in.h>
  36. #include <netinet/in_systm.h>
  37. #include <netinet/ip.h>
  38. #include <netinet/if_ether.h>
  39. #include <netinet/ip_var.h>
  40. #include <netinet/udp.h>
  41. #include <netinet/udp_var.h>
  42. #include <netinet/tcp.h>
  43. #include <netinet/tcpip.h>
  44. #include <ctype.h>
  45. #include <errno.h>
  46. #include <stdio.h>
  47. #include "pcap-int.h"
  48. #ifdef HAVE_OS_PROTO_H
  49. #include "os-proto.h"
  50. #endif
  51. /*
  52. * The chunk size for NIT. This is the amount of buffering
  53. * done for read calls.
  54. */
  55. #define CHUNKSIZE (2*1024)
  56. /*
  57. * The total buffer space used by NIT.
  58. */
  59. #define BUFSPACE (4*CHUNKSIZE)
  60. /* Forwards */
  61. static int nit_setflags(int, int, int, char *);
  62. /*
  63. * Private data for capturing on NIT devices.
  64. */
  65. struct pcap_nit {
  66. struct pcap_stat stat;
  67. };
  68. static int
  69. pcap_stats_nit(pcap_t *p, struct pcap_stat *ps)
  70. {
  71. struct pcap_nit *pn = p->priv;
  72. /*
  73. * "ps_recv" counts packets handed to the filter, not packets
  74. * that passed the filter. As filtering is done in userland,
  75. * this does not include packets dropped because we ran out
  76. * of buffer space.
  77. *
  78. * "ps_drop" presumably counts packets dropped by the socket
  79. * because of flow control requirements or resource exhaustion;
  80. * it doesn't count packets dropped by the interface driver.
  81. * As filtering is done in userland, it counts packets regardless
  82. * of whether they would've passed the filter.
  83. *
  84. * These statistics don't include packets not yet read from the
  85. * kernel by libpcap or packets not yet read from libpcap by the
  86. * application.
  87. */
  88. *ps = pn->stat;
  89. return (0);
  90. }
  91. static int
  92. pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
  93. {
  94. struct pcap_nit *pn = p->priv;
  95. register int cc, n;
  96. register u_char *bp, *cp, *ep;
  97. register struct nit_hdr *nh;
  98. register int caplen;
  99. cc = p->cc;
  100. if (cc == 0) {
  101. cc = read(p->fd, (char *)p->buffer, p->bufsize);
  102. if (cc < 0) {
  103. if (errno == EWOULDBLOCK)
  104. return (0);
  105. snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s",
  106. pcap_strerror(errno));
  107. return (-1);
  108. }
  109. bp = p->buffer;
  110. } else
  111. bp = p->bp;
  112. /*
  113. * Loop through each packet. The increment expression
  114. * rounds up to the next int boundary past the end of
  115. * the previous packet.
  116. */
  117. n = 0;
  118. ep = bp + cc;
  119. while (bp < ep) {
  120. /*
  121. * Has "pcap_breakloop()" been called?
  122. * If so, return immediately - if we haven't read any
  123. * packets, clear the flag and return -2 to indicate
  124. * that we were told to break out of the loop, otherwise
  125. * leave the flag set, so that the *next* call will break
  126. * out of the loop without having read any packets, and
  127. * return the number of packets we've processed so far.
  128. */
  129. if (p->break_loop) {
  130. if (n == 0) {
  131. p->break_loop = 0;
  132. return (-2);
  133. } else {
  134. p->cc = ep - bp;
  135. p->bp = bp;
  136. return (n);
  137. }
  138. }
  139. nh = (struct nit_hdr *)bp;
  140. cp = bp + sizeof(*nh);
  141. switch (nh->nh_state) {
  142. case NIT_CATCH:
  143. break;
  144. case NIT_NOMBUF:
  145. case NIT_NOCLUSTER:
  146. case NIT_NOSPACE:
  147. pn->stat.ps_drop = nh->nh_dropped;
  148. continue;
  149. case NIT_SEQNO:
  150. continue;
  151. default:
  152. snprintf(p->errbuf, sizeof(p->errbuf),
  153. "bad nit state %d", nh->nh_state);
  154. return (-1);
  155. }
  156. ++pn->stat.ps_recv;
  157. bp += ((sizeof(struct nit_hdr) + nh->nh_datalen +
  158. sizeof(int) - 1) & ~(sizeof(int) - 1));
  159. caplen = nh->nh_wirelen;
  160. if (caplen > p->snapshot)
  161. caplen = p->snapshot;
  162. if (bpf_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) {
  163. struct pcap_pkthdr h;
  164. h.ts = nh->nh_timestamp;
  165. h.len = nh->nh_wirelen;
  166. h.caplen = caplen;
  167. (*callback)(user, &h, cp);
  168. if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
  169. p->cc = ep - bp;
  170. p->bp = bp;
  171. return (n);
  172. }
  173. }
  174. }
  175. p->cc = 0;
  176. return (n);
  177. }
  178. static int
  179. pcap_inject_nit(pcap_t *p, const void *buf, size_t size)
  180. {
  181. struct sockaddr sa;
  182. int ret;
  183. memset(&sa, 0, sizeof(sa));
  184. strncpy(sa.sa_data, device, sizeof(sa.sa_data));
  185. ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa));
  186. if (ret == -1) {
  187. snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
  188. pcap_strerror(errno));
  189. return (-1);
  190. }
  191. return (ret);
  192. }
  193. static int
  194. nit_setflags(pcap_t *p)
  195. {
  196. struct nit_ioc nioc;
  197. memset(&nioc, 0, sizeof(nioc));
  198. nioc.nioc_typetomatch = NT_ALLTYPES;
  199. nioc.nioc_snaplen = p->snapshot;
  200. nioc.nioc_bufalign = sizeof(int);
  201. nioc.nioc_bufoffset = 0;
  202. if (p->opt.buffer_size != 0)
  203. nioc.nioc_bufspace = p->opt.buffer_size;
  204. else {
  205. /* Default buffer size */
  206. nioc.nioc_bufspace = BUFSPACE;
  207. }
  208. if (p->opt.immediate) {
  209. /*
  210. * XXX - will this cause packets to be delivered immediately?
  211. * XXX - given that this is for SunOS prior to 4.0, do
  212. * we care?
  213. */
  214. nioc.nioc_chunksize = 0;
  215. } else
  216. nioc.nioc_chunksize = CHUNKSIZE;
  217. if (p->opt.timeout != 0) {
  218. nioc.nioc_flags |= NF_TIMEOUT;
  219. nioc.nioc_timeout.tv_sec = p->opt.timeout / 1000;
  220. nioc.nioc_timeout.tv_usec = (p->opt.timeout * 1000) % 1000000;
  221. }
  222. if (p->opt.promisc)
  223. nioc.nioc_flags |= NF_PROMISC;
  224. if (ioctl(p->fd, SIOCSNIT, &nioc) < 0) {
  225. snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNIT: %s",
  226. pcap_strerror(errno));
  227. return (-1);
  228. }
  229. return (0);
  230. }
  231. static int
  232. pcap_activate_nit(pcap_t *p)
  233. {
  234. int fd;
  235. struct sockaddr_nit snit;
  236. if (p->opt.rfmon) {
  237. /*
  238. * No monitor mode on SunOS 3.x or earlier (no
  239. * Wi-Fi *devices* for the hardware that supported
  240. * them!).
  241. */
  242. return (PCAP_ERROR_RFMON_NOTSUP);
  243. }
  244. if (p->snapshot < 96)
  245. /*
  246. * NIT requires a snapshot length of at least 96.
  247. */
  248. p->snapshot = 96;
  249. memset(p, 0, sizeof(*p));
  250. p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
  251. if (fd < 0) {
  252. snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
  253. "socket: %s", pcap_strerror(errno));
  254. goto bad;
  255. }
  256. snit.snit_family = AF_NIT;
  257. (void)strncpy(snit.snit_ifname, p->opt.source, NITIFSIZ);
  258. if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
  259. snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
  260. "bind: %s: %s", snit.snit_ifname, pcap_strerror(errno));
  261. goto bad;
  262. }
  263. if (nit_setflags(p) < 0)
  264. goto bad;
  265. /*
  266. * NIT supports only ethernets.
  267. */
  268. p->linktype = DLT_EN10MB;
  269. p->bufsize = BUFSPACE;
  270. p->buffer = (u_char *)malloc(p->bufsize);
  271. if (p->buffer == NULL) {
  272. strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
  273. goto bad;
  274. }
  275. /*
  276. * "p->fd" is a socket, so "select()" should work on it.
  277. */
  278. p->selectable_fd = p->fd;
  279. /*
  280. * This is (presumably) a real Ethernet capture; give it a
  281. * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
  282. * that an application can let you choose it, in case you're
  283. * capturing DOCSIS traffic that a Cisco Cable Modem
  284. * Termination System is putting out onto an Ethernet (it
  285. * doesn't put an Ethernet header onto the wire, it puts raw
  286. * DOCSIS frames out on the wire inside the low-level
  287. * Ethernet framing).
  288. */
  289. p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
  290. /*
  291. * If that fails, just leave the list empty.
  292. */
  293. if (p->dlt_list != NULL) {
  294. p->dlt_list[0] = DLT_EN10MB;
  295. p->dlt_list[1] = DLT_DOCSIS;
  296. p->dlt_count = 2;
  297. }
  298. p->read_op = pcap_read_nit;
  299. p->inject_op = pcap_inject_nit;
  300. p->setfilter_op = install_bpf_program; /* no kernel filtering */
  301. p->setdirection_op = NULL; /* Not implemented. */
  302. p->set_datalink_op = NULL; /* can't change data link type */
  303. p->getnonblock_op = pcap_getnonblock_fd;
  304. p->setnonblock_op = pcap_setnonblock_fd;
  305. p->stats_op = pcap_stats_nit;
  306. return (0);
  307. bad:
  308. pcap_cleanup_live_common(p);
  309. return (PCAP_ERROR);
  310. }
  311. pcap_t *
  312. pcap_create_interface(const char *device, char *ebuf)
  313. {
  314. pcap_t *p;
  315. p = pcap_create_common(device, ebuf, sizeof (struct pcap_nit));
  316. if (p == NULL)
  317. return (NULL);
  318. p->activate_op = pcap_activate_nit;
  319. return (p);
  320. }
  321. int
  322. pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
  323. {
  324. return (0);
  325. }