isis_bpf.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * IS-IS Rout(e)ing protocol - isis_bpf.c
  3. *
  4. * Copyright (C) 2001,2002 Sampo Saaristo
  5. * Tampere University of Technology
  6. * Institute of Communications Engineering
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public Licenseas published by the Free
  10. * Software Foundation; either version 2 of the License, or (at your option)
  11. * any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. * more details.
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, write to the Free Software Foundation, Inc.,
  19. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. */
  21. #include <zebra.h>
  22. #if ISIS_METHOD == ISIS_METHOD_BPF
  23. #include <net/if.h>
  24. #include <netinet/if_ether.h>
  25. #include <sys/time.h>
  26. #include <sys/ioctl.h>
  27. #include <net/bpf.h>
  28. #include "log.h"
  29. #include "network.h"
  30. #include "stream.h"
  31. #include "if.h"
  32. #include "isisd/dict.h"
  33. #include "isisd/include-netbsd/iso.h"
  34. #include "isisd/isis_constants.h"
  35. #include "isisd/isis_common.h"
  36. #include "isisd/isis_circuit.h"
  37. #include "isisd/isis_flags.h"
  38. #include "isisd/isisd.h"
  39. #include "isisd/isis_constants.h"
  40. #include "isisd/isis_circuit.h"
  41. #include "isisd/isis_network.h"
  42. #include "privs.h"
  43. extern struct zebra_privs_t isisd_privs;
  44. struct bpf_insn llcfilter[] = {
  45. BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN), /* check first byte */
  46. BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5),
  47. BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1),
  48. BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3), /* check second byte */
  49. BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2),
  50. BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1), /* check third byte */
  51. BPF_STMT (BPF_RET + BPF_K, (u_int) - 1),
  52. BPF_STMT (BPF_RET + BPF_K, 0)
  53. };
  54. u_int readblen = 0;
  55. u_char *readbuff = NULL;
  56. /*
  57. * Table 9 - Architectural constants for use with ISO 8802 subnetworks
  58. * ISO 10589 - 8.4.8
  59. */
  60. u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
  61. u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
  62. u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
  63. u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
  64. static char sock_buff[8192];
  65. static int
  66. open_bpf_dev (struct isis_circuit *circuit)
  67. {
  68. int i = 0, fd;
  69. char bpfdev[128];
  70. struct ifreq ifr;
  71. u_int blen, immediate, seesent;
  72. struct timeval timeout;
  73. struct bpf_program bpf_prog;
  74. do
  75. {
  76. (void) snprintf (bpfdev, sizeof (bpfdev), "/dev/bpf%d", i++);
  77. fd = open (bpfdev, O_RDWR);
  78. }
  79. while (fd < 0 && errno == EBUSY);
  80. if (fd < 0)
  81. {
  82. zlog_warn ("open_bpf_dev(): failed to create bpf socket: %s",
  83. safe_strerror (errno));
  84. return ISIS_WARNING;
  85. }
  86. zlog_debug ("Opened BPF device %s", bpfdev);
  87. memcpy (ifr.ifr_name, circuit->interface->name, sizeof (ifr.ifr_name));
  88. if (ioctl (fd, BIOCSETIF, (caddr_t) & ifr) < 0)
  89. {
  90. zlog_warn ("open_bpf_dev(): failed to bind to interface: %s",
  91. safe_strerror (errno));
  92. return ISIS_WARNING;
  93. }
  94. if (ioctl (fd, BIOCGBLEN, (caddr_t) & blen) < 0)
  95. {
  96. zlog_warn ("failed to get BPF buffer len");
  97. blen = circuit->interface->mtu;
  98. }
  99. readblen = blen;
  100. if (readbuff == NULL)
  101. readbuff = malloc (blen);
  102. zlog_debug ("BPF buffer len = %u", blen);
  103. /* BPF(4): reads return immediately upon packet reception.
  104. * Otherwise, a read will block until either the kernel
  105. * buffer becomes full or a timeout occurs.
  106. */
  107. immediate = 1;
  108. if (ioctl (fd, BIOCIMMEDIATE, (caddr_t) & immediate) < 0)
  109. {
  110. zlog_warn ("failed to set BPF dev to immediate mode");
  111. }
  112. #ifdef BIOCSSEESENT
  113. /*
  114. * We want to see only incoming packets
  115. */
  116. seesent = 0;
  117. if (ioctl (fd, BIOCSSEESENT, (caddr_t) & seesent) < 0)
  118. {
  119. zlog_warn ("failed to set BPF dev to incoming only mode");
  120. }
  121. #endif
  122. /*
  123. * ...but all of them
  124. */
  125. if (ioctl (fd, BIOCPROMISC) < 0)
  126. {
  127. zlog_warn ("failed to set BPF dev to promiscuous mode");
  128. }
  129. /*
  130. * If the buffer length is smaller than our mtu, lets try to increase it
  131. */
  132. if (blen < circuit->interface->mtu)
  133. {
  134. if (ioctl (fd, BIOCSBLEN, &circuit->interface->mtu) < 0)
  135. {
  136. zlog_warn ("failed to set BPF buffer len (%u to %u)", blen,
  137. circuit->interface->mtu);
  138. }
  139. }
  140. /*
  141. * Set a timeout parameter - hope this helps select()
  142. */
  143. timeout.tv_sec = 600;
  144. timeout.tv_usec = 0;
  145. if (ioctl (fd, BIOCSRTIMEOUT, (caddr_t) & timeout) < 0)
  146. {
  147. zlog_warn ("failed to set BPF device timeout");
  148. }
  149. /*
  150. * And set the filter
  151. */
  152. memset (&bpf_prog, 0, sizeof (struct bpf_program));
  153. bpf_prog.bf_len = 8;
  154. bpf_prog.bf_insns = &(llcfilter[0]);
  155. if (ioctl (fd, BIOCSETF, (caddr_t) & bpf_prog) < 0)
  156. {
  157. zlog_warn ("open_bpf_dev(): failed to install filter: %s",
  158. safe_strerror (errno));
  159. return ISIS_WARNING;
  160. }
  161. assert (fd > 0);
  162. circuit->fd = fd;
  163. return ISIS_OK;
  164. }
  165. /*
  166. * Create the socket and set the tx/rx funcs
  167. */
  168. int
  169. isis_sock_init (struct isis_circuit *circuit)
  170. {
  171. int retval = ISIS_OK;
  172. if (isisd_privs.change (ZPRIVS_RAISE))
  173. zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
  174. retval = open_bpf_dev (circuit);
  175. if (retval != ISIS_OK)
  176. {
  177. zlog_warn ("%s: could not initialize the socket", __func__);
  178. goto end;
  179. }
  180. if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  181. {
  182. circuit->tx = isis_send_pdu_bcast;
  183. circuit->rx = isis_recv_pdu_bcast;
  184. }
  185. else if (circuit->circ_type == CIRCUIT_T_P2P)
  186. {
  187. circuit->tx = isis_send_pdu_p2p;
  188. circuit->rx = isis_recv_pdu_p2p;
  189. }
  190. else
  191. {
  192. zlog_warn ("isis_sock_init(): unknown circuit type");
  193. retval = ISIS_WARNING;
  194. goto end;
  195. }
  196. end:
  197. if (isisd_privs.change (ZPRIVS_LOWER))
  198. zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
  199. return retval;
  200. }
  201. int
  202. isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
  203. {
  204. int bytesread = 0, bytestoread, offset, one = 1;
  205. struct bpf_hdr *bpf_hdr;
  206. assert (circuit->fd > 0);
  207. if (ioctl (circuit->fd, FIONREAD, (caddr_t) & bytestoread) < 0)
  208. {
  209. zlog_warn ("ioctl() FIONREAD failed: %s", safe_strerror (errno));
  210. }
  211. if (bytestoread)
  212. {
  213. bytesread = read (circuit->fd, readbuff, readblen);
  214. }
  215. if (bytesread < 0)
  216. {
  217. zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s",
  218. safe_strerror (errno));
  219. return ISIS_WARNING;
  220. }
  221. if (bytesread == 0)
  222. return ISIS_WARNING;
  223. bpf_hdr = (struct bpf_hdr *) readbuff;
  224. assert (bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
  225. offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
  226. /* then we lose the BPF, LLC and ethernet headers */
  227. stream_write (circuit->rcv_stream, readbuff + offset,
  228. bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
  229. stream_set_getp (circuit->rcv_stream, 0);
  230. memcpy (ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN,
  231. ETHER_ADDR_LEN);
  232. if (ioctl (circuit->fd, BIOCFLUSH, &one) < 0)
  233. zlog_warn ("Flushing failed: %s", safe_strerror (errno));
  234. return ISIS_OK;
  235. }
  236. int
  237. isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
  238. {
  239. int bytesread;
  240. bytesread = stream_read (circuit->rcv_stream, circuit->fd,
  241. circuit->interface->mtu);
  242. if (bytesread < 0)
  243. {
  244. zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno));
  245. return ISIS_WARNING;
  246. }
  247. return ISIS_OK;
  248. }
  249. int
  250. isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
  251. {
  252. struct ether_header *eth;
  253. ssize_t written;
  254. size_t buflen;
  255. buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN;
  256. if (buflen > sizeof (sock_buff))
  257. {
  258. zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than "
  259. "output pdu size %zu on circuit %s",
  260. sizeof (sock_buff), buflen, circuit->interface->name);
  261. return ISIS_WARNING;
  262. }
  263. stream_set_getp (circuit->snd_stream, 0);
  264. /*
  265. * First the eth header
  266. */
  267. eth = (struct ether_header *) sock_buff;
  268. if (level == 1)
  269. memcpy (eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN);
  270. else
  271. memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
  272. memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
  273. eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
  274. /*
  275. * Then the LLC
  276. */
  277. sock_buff[ETHER_HDR_LEN] = ISO_SAP;
  278. sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
  279. sock_buff[ETHER_HDR_LEN + 2] = 0x03;
  280. /* then we copy the data */
  281. memcpy (sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
  282. stream_get_endp (circuit->snd_stream));
  283. /* now we can send this */
  284. written = write (circuit->fd, sock_buff, buflen);
  285. if (written < 0)
  286. {
  287. zlog_warn("IS-IS bpf: could not transmit packet on %s: %s",
  288. circuit->interface->name, safe_strerror(errno));
  289. if (ERRNO_IO_RETRY(errno))
  290. return ISIS_WARNING;
  291. return ISIS_ERROR;
  292. }
  293. return ISIS_OK;
  294. }
  295. int
  296. isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
  297. {
  298. return ISIS_OK;
  299. }
  300. #endif /* ISIS_METHOD == ISIS_METHOD_BPF */