pcap-libdlpi.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. * Copyright (c) 1993, 1994, 1995, 1996, 1997
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that: (1) source code distributions
  7. * retain the above copyright notice and this paragraph in its entirety, (2)
  8. * distributions including binary code include the above copyright notice and
  9. * this paragraph in its entirety in the documentation or other materials
  10. * provided with the distribution, and (3) all advertising materials mentioning
  11. * features or use of this software display the following acknowledgement:
  12. * ``This product includes software developed by the University of California,
  13. * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14. * the University nor the names of its contributors may be used to endorse
  15. * or promote products derived from this software without specific prior
  16. * written permission.
  17. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20. *
  21. * This code contributed by Sagun Shakya (sagun.shakya@sun.com)
  22. */
  23. /*
  24. * Packet capture routines for DLPI using libdlpi under SunOS 5.11.
  25. */
  26. #ifdef HAVE_CONFIG_H
  27. #include <config.h>
  28. #endif
  29. #include <sys/types.h>
  30. #include <sys/time.h>
  31. #include <sys/bufmod.h>
  32. #include <sys/stream.h>
  33. #include <libdlpi.h>
  34. #include <errno.h>
  35. #include <memory.h>
  36. #include <stropts.h>
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include "pcap-int.h"
  41. #include "dlpisubs.h"
  42. /* Forwards. */
  43. static int dlpromiscon(pcap_t *, bpf_u_int32);
  44. static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *);
  45. static int pcap_inject_libdlpi(pcap_t *, const void *, size_t);
  46. static void pcap_libdlpi_err(const char *, const char *, int, char *);
  47. static void pcap_cleanup_libdlpi(pcap_t *);
  48. /*
  49. * list_interfaces() will list all the network links that are
  50. * available on a system.
  51. */
  52. static boolean_t list_interfaces(const char *, void *);
  53. typedef struct linknamelist {
  54. char linkname[DLPI_LINKNAME_MAX];
  55. struct linknamelist *lnl_next;
  56. } linknamelist_t;
  57. typedef struct linkwalk {
  58. linknamelist_t *lw_list;
  59. int lw_err;
  60. } linkwalk_t;
  61. /*
  62. * The caller of this function should free the memory allocated
  63. * for each linknamelist_t "entry" allocated.
  64. */
  65. static boolean_t
  66. list_interfaces(const char *linkname, void *arg)
  67. {
  68. linkwalk_t *lwp = arg;
  69. linknamelist_t *entry;
  70. if ((entry = calloc(1, sizeof(linknamelist_t))) == NULL) {
  71. lwp->lw_err = ENOMEM;
  72. return (B_TRUE);
  73. }
  74. (void) strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX);
  75. if (lwp->lw_list == NULL) {
  76. lwp->lw_list = entry;
  77. } else {
  78. entry->lnl_next = lwp->lw_list;
  79. lwp->lw_list = entry;
  80. }
  81. return (B_FALSE);
  82. }
  83. static int
  84. pcap_activate_libdlpi(pcap_t *p)
  85. {
  86. struct pcap_dlpi *pd = p->priv;
  87. int status = 0;
  88. int retv;
  89. dlpi_handle_t dh;
  90. dlpi_info_t dlinfo;
  91. /*
  92. * Enable Solaris raw and passive DLPI extensions;
  93. * dlpi_open() will not fail if the underlying link does not support
  94. * passive mode. See dlpi(7P) for details.
  95. */
  96. retv = dlpi_open(p->opt.device, &dh, DLPI_RAW|DLPI_PASSIVE);
  97. if (retv != DLPI_SUCCESS) {
  98. if (retv == DLPI_ELINKNAMEINVAL || retv == DLPI_ENOLINK)
  99. status = PCAP_ERROR_NO_SUCH_DEVICE;
  100. else if (retv == DL_SYSERR &&
  101. (errno == EPERM || errno == EACCES))
  102. status = PCAP_ERROR_PERM_DENIED;
  103. else
  104. status = PCAP_ERROR;
  105. pcap_libdlpi_err(p->opt.device, "dlpi_open", retv,
  106. p->errbuf);
  107. return (status);
  108. }
  109. pd->dlpi_hd = dh;
  110. if (p->opt.rfmon) {
  111. /*
  112. * This device exists, but we don't support monitor mode
  113. * any platforms that support DLPI.
  114. */
  115. status = PCAP_ERROR_RFMON_NOTSUP;
  116. goto bad;
  117. }
  118. /* Bind with DLPI_ANY_SAP. */
  119. if ((retv = dlpi_bind(pd->dlpi_hd, DLPI_ANY_SAP, 0)) != DLPI_SUCCESS) {
  120. status = PCAP_ERROR;
  121. pcap_libdlpi_err(p->opt.device, "dlpi_bind", retv, p->errbuf);
  122. goto bad;
  123. }
  124. /*
  125. * Turn a negative snapshot value (invalid), a snapshot value of
  126. * 0 (unspecified), or a value bigger than the normal maximum
  127. * value, into the maximum allowed value.
  128. *
  129. * If some application really *needs* a bigger snapshot
  130. * length, we should just increase MAXIMUM_SNAPLEN.
  131. */
  132. if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
  133. p->snapshot = MAXIMUM_SNAPLEN;
  134. /* Enable promiscuous mode. */
  135. if (p->opt.promisc) {
  136. retv = dlpromiscon(p, DL_PROMISC_PHYS);
  137. if (retv < 0) {
  138. /*
  139. * "You don't have permission to capture on
  140. * this device" and "you don't have permission
  141. * to capture in promiscuous mode on this
  142. * device" are different; let the user know,
  143. * so if they can't get permission to
  144. * capture in promiscuous mode, they can at
  145. * least try to capture in non-promiscuous
  146. * mode.
  147. *
  148. * XXX - you might have to capture in
  149. * promiscuous mode to see outgoing packets.
  150. */
  151. if (retv == PCAP_ERROR_PERM_DENIED)
  152. status = PCAP_ERROR_PROMISC_PERM_DENIED;
  153. else
  154. status = retv;
  155. goto bad;
  156. }
  157. } else {
  158. /* Try to enable multicast. */
  159. retv = dlpromiscon(p, DL_PROMISC_MULTI);
  160. if (retv < 0) {
  161. status = retv;
  162. goto bad;
  163. }
  164. }
  165. /* Try to enable SAP promiscuity. */
  166. retv = dlpromiscon(p, DL_PROMISC_SAP);
  167. if (retv < 0) {
  168. /*
  169. * Not fatal, since the DL_PROMISC_PHYS mode worked.
  170. * Report it as a warning, however.
  171. */
  172. if (p->opt.promisc)
  173. status = PCAP_WARNING;
  174. else {
  175. status = retv;
  176. goto bad;
  177. }
  178. }
  179. /* Determine link type. */
  180. if ((retv = dlpi_info(pd->dlpi_hd, &dlinfo, 0)) != DLPI_SUCCESS) {
  181. status = PCAP_ERROR;
  182. pcap_libdlpi_err(p->opt.device, "dlpi_info", retv, p->errbuf);
  183. goto bad;
  184. }
  185. if (pcap_process_mactype(p, dlinfo.di_mactype) != 0) {
  186. status = PCAP_ERROR;
  187. goto bad;
  188. }
  189. p->fd = dlpi_fd(pd->dlpi_hd);
  190. /* Push and configure bufmod. */
  191. if (pcap_conf_bufmod(p, p->snapshot) != 0) {
  192. status = PCAP_ERROR;
  193. goto bad;
  194. }
  195. /*
  196. * Flush the read side.
  197. */
  198. if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
  199. status = PCAP_ERROR;
  200. pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
  201. errno, "FLUSHR");
  202. goto bad;
  203. }
  204. /* Allocate data buffer. */
  205. if (pcap_alloc_databuf(p) != 0) {
  206. status = PCAP_ERROR;
  207. goto bad;
  208. }
  209. /*
  210. * "p->fd" is a FD for a STREAMS device, so "select()" and
  211. * "poll()" should work on it.
  212. */
  213. p->selectable_fd = p->fd;
  214. p->read_op = pcap_read_libdlpi;
  215. p->inject_op = pcap_inject_libdlpi;
  216. p->setfilter_op = install_bpf_program; /* No kernel filtering */
  217. p->setdirection_op = NULL; /* Not implemented */
  218. p->set_datalink_op = NULL; /* Can't change data link type */
  219. p->getnonblock_op = pcap_getnonblock_fd;
  220. p->setnonblock_op = pcap_setnonblock_fd;
  221. p->stats_op = pcap_stats_dlpi;
  222. p->cleanup_op = pcap_cleanup_libdlpi;
  223. return (status);
  224. bad:
  225. pcap_cleanup_libdlpi(p);
  226. return (status);
  227. }
  228. #define STRINGIFY(n) #n
  229. static int
  230. dlpromiscon(pcap_t *p, bpf_u_int32 level)
  231. {
  232. struct pcap_dlpi *pd = p->priv;
  233. int retv;
  234. int err;
  235. retv = dlpi_promiscon(pd->dlpi_hd, level);
  236. if (retv != DLPI_SUCCESS) {
  237. if (retv == DL_SYSERR &&
  238. (errno == EPERM || errno == EACCES))
  239. err = PCAP_ERROR_PERM_DENIED;
  240. else
  241. err = PCAP_ERROR;
  242. pcap_libdlpi_err(p->opt.device, "dlpi_promiscon" STRINGIFY(level),
  243. retv, p->errbuf);
  244. return (err);
  245. }
  246. return (0);
  247. }
  248. /*
  249. * Presumably everything returned by dlpi_walk() is a DLPI device,
  250. * so there's no work to be done here to check whether name refers
  251. * to a DLPI device.
  252. */
  253. static int
  254. is_dlpi_interface(const char *name _U_)
  255. {
  256. return (1);
  257. }
  258. static int
  259. get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_)
  260. {
  261. /*
  262. * Nothing we can do other than mark loopback devices as "the
  263. * connected/disconnected status doesn't apply".
  264. *
  265. * XXX - on Solaris, can we do what the dladm command does,
  266. * i.e. get a connected/disconnected indication from a kstat?
  267. * (Note that you can also get the link speed, and possibly
  268. * other information, from a kstat as well.)
  269. */
  270. if (*flags & PCAP_IF_LOOPBACK) {
  271. /*
  272. * Loopback devices aren't wireless, and "connected"/
  273. * "disconnected" doesn't apply to them.
  274. */
  275. *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
  276. return (0);
  277. }
  278. return (0);
  279. }
  280. /*
  281. * In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find
  282. * network links that are plumbed and are up. dlpi_walk(3DLPI) will find
  283. * additional network links present in the system.
  284. */
  285. int
  286. pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
  287. {
  288. int retv = 0;
  289. linknamelist_t *entry, *next;
  290. linkwalk_t lw = {NULL, 0};
  291. int save_errno;
  292. /*
  293. * Get the list of regular interfaces first.
  294. */
  295. if (pcap_findalldevs_interfaces(devlistp, errbuf,
  296. is_dlpi_interface, get_if_flags) == -1)
  297. return (-1); /* failure */
  298. /* dlpi_walk() for loopback will be added here. */
  299. /*
  300. * Find all DLPI devices in the current zone.
  301. *
  302. * XXX - will pcap_findalldevs_interfaces() find any devices
  303. * outside the current zone? If not, the only reason to call
  304. * it would be to get the interface addresses.
  305. */
  306. dlpi_walk(list_interfaces, &lw, 0);
  307. if (lw.lw_err != 0) {
  308. pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
  309. lw.lw_err, "dlpi_walk");
  310. retv = -1;
  311. goto done;
  312. }
  313. /* Add linkname if it does not exist on the list. */
  314. for (entry = lw.lw_list; entry != NULL; entry = entry->lnl_next) {
  315. /*
  316. * If it isn't already in the list of devices, try to
  317. * add it.
  318. */
  319. if (find_or_add_dev(devlistp, entry->linkname, 0, get_if_flags,
  320. NULL, errbuf) == NULL)
  321. retv = -1;
  322. }
  323. done:
  324. save_errno = errno;
  325. for (entry = lw.lw_list; entry != NULL; entry = next) {
  326. next = entry->lnl_next;
  327. free(entry);
  328. }
  329. errno = save_errno;
  330. return (retv);
  331. }
  332. /*
  333. * Read data received on DLPI handle. Returns -2 if told to terminate, else
  334. * returns the number of packets read.
  335. */
  336. static int
  337. pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user)
  338. {
  339. struct pcap_dlpi *pd = p->priv;
  340. int len;
  341. u_char *bufp;
  342. size_t msglen;
  343. int retv;
  344. len = p->cc;
  345. if (len != 0) {
  346. bufp = p->bp;
  347. goto process_pkts;
  348. }
  349. do {
  350. /* Has "pcap_breakloop()" been called? */
  351. if (p->break_loop) {
  352. /*
  353. * Yes - clear the flag that indicates that it has,
  354. * and return -2 to indicate that we were told to
  355. * break out of the loop.
  356. */
  357. p->break_loop = 0;
  358. return (-2);
  359. }
  360. msglen = p->bufsize;
  361. bufp = (u_char *)p->buffer + p->offset;
  362. retv = dlpi_recv(pd->dlpi_hd, NULL, NULL, bufp,
  363. &msglen, -1, NULL);
  364. if (retv != DLPI_SUCCESS) {
  365. /*
  366. * This is most likely a call to terminate out of the
  367. * loop. So, do not return an error message, instead
  368. * check if "pcap_breakloop()" has been called above.
  369. */
  370. if (retv == DL_SYSERR && errno == EINTR) {
  371. len = 0;
  372. continue;
  373. }
  374. pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd),
  375. "dlpi_recv", retv, p->errbuf);
  376. return (-1);
  377. }
  378. len = msglen;
  379. } while (len == 0);
  380. process_pkts:
  381. return (pcap_process_pkts(p, callback, user, count, bufp, len));
  382. }
  383. static int
  384. pcap_inject_libdlpi(pcap_t *p, const void *buf, size_t size)
  385. {
  386. struct pcap_dlpi *pd = p->priv;
  387. int retv;
  388. retv = dlpi_send(pd->dlpi_hd, NULL, 0, buf, size, NULL);
  389. if (retv != DLPI_SUCCESS) {
  390. pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), "dlpi_send", retv,
  391. p->errbuf);
  392. return (-1);
  393. }
  394. /*
  395. * dlpi_send(3DLPI) does not provide a way to return the number of
  396. * bytes sent on the wire. Based on the fact that DLPI_SUCCESS was
  397. * returned we are assuming 'size' bytes were sent.
  398. */
  399. return (size);
  400. }
  401. /*
  402. * Close dlpi handle.
  403. */
  404. static void
  405. pcap_cleanup_libdlpi(pcap_t *p)
  406. {
  407. struct pcap_dlpi *pd = p->priv;
  408. if (pd->dlpi_hd != NULL) {
  409. dlpi_close(pd->dlpi_hd);
  410. pd->dlpi_hd = NULL;
  411. p->fd = -1;
  412. }
  413. pcap_cleanup_live_common(p);
  414. }
  415. /*
  416. * Write error message to buffer.
  417. */
  418. static void
  419. pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf)
  420. {
  421. pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s",
  422. func, linkname, dlpi_strerror(err));
  423. }
  424. pcap_t *
  425. pcap_create_interface(const char *device _U_, char *ebuf)
  426. {
  427. pcap_t *p;
  428. p = pcap_create_common(ebuf, sizeof (struct pcap_dlpi));
  429. if (p == NULL)
  430. return (NULL);
  431. p->activate_op = pcap_activate_libdlpi;
  432. return (p);
  433. }
  434. /*
  435. * Libpcap version string.
  436. */
  437. const char *
  438. pcap_lib_version(void)
  439. {
  440. return (PCAP_VERSION_STRING);
  441. }