isis_pfpacket.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. * IS-IS Rout(e)ing protocol - isis_pfpacket.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_PFPACKET
  23. #include <net/ethernet.h> /* the L2 protocols */
  24. #include <netpacket/packet.h>
  25. #include "log.h"
  26. #include "network.h"
  27. #include "stream.h"
  28. #include "if.h"
  29. #include "isisd/dict.h"
  30. #include "isisd/include-netbsd/iso.h"
  31. #include "isisd/isis_constants.h"
  32. #include "isisd/isis_common.h"
  33. #include "isisd/isis_circuit.h"
  34. #include "isisd/isis_flags.h"
  35. #include "isisd/isisd.h"
  36. #include "isisd/isis_constants.h"
  37. #include "isisd/isis_circuit.h"
  38. #include "isisd/isis_network.h"
  39. #include "privs.h"
  40. extern struct zebra_privs_t isisd_privs;
  41. /*
  42. * Table 9 - Architectural constants for use with ISO 8802 subnetworks
  43. * ISO 10589 - 8.4.8
  44. */
  45. u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
  46. u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
  47. u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
  48. u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
  49. static uint8_t discard_buff[8192];
  50. static uint8_t sock_buff[8192];
  51. /*
  52. * if level is 0 we are joining p2p multicast
  53. * FIXME: and the p2p multicast being ???
  54. */
  55. static int
  56. isis_multicast_join (int fd, int registerto, int if_num)
  57. {
  58. struct packet_mreq mreq;
  59. memset (&mreq, 0, sizeof (mreq));
  60. mreq.mr_ifindex = if_num;
  61. if (registerto)
  62. {
  63. mreq.mr_type = PACKET_MR_MULTICAST;
  64. mreq.mr_alen = ETH_ALEN;
  65. if (registerto == 1)
  66. memcpy (&mreq.mr_address, ALL_L1_ISS, ETH_ALEN);
  67. else if (registerto == 2)
  68. memcpy (&mreq.mr_address, ALL_L2_ISS, ETH_ALEN);
  69. else if (registerto == 3)
  70. memcpy (&mreq.mr_address, ALL_ISS, ETH_ALEN);
  71. else
  72. memcpy (&mreq.mr_address, ALL_ESS, ETH_ALEN);
  73. }
  74. else
  75. {
  76. mreq.mr_type = PACKET_MR_ALLMULTI;
  77. }
  78. #ifdef EXTREME_DEBUG
  79. zlog_debug ("isis_multicast_join(): fd=%d, reg_to=%d, if_num=%d, "
  80. "address = %02x:%02x:%02x:%02x:%02x:%02x",
  81. fd, registerto, if_num, mreq.mr_address[0], mreq.mr_address[1],
  82. mreq.mr_address[2], mreq.mr_address[3], mreq.mr_address[4],
  83. mreq.mr_address[5]);
  84. #endif /* EXTREME_DEBUG */
  85. if (setsockopt (fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
  86. sizeof (struct packet_mreq)))
  87. {
  88. zlog_warn ("isis_multicast_join(): setsockopt(): %s", safe_strerror (errno));
  89. return ISIS_WARNING;
  90. }
  91. return ISIS_OK;
  92. }
  93. static int
  94. open_packet_socket (struct isis_circuit *circuit)
  95. {
  96. struct sockaddr_ll s_addr;
  97. int fd, retval = ISIS_OK;
  98. fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
  99. if (fd < 0)
  100. {
  101. zlog_warn ("open_packet_socket(): socket() failed %s",
  102. safe_strerror (errno));
  103. return ISIS_WARNING;
  104. }
  105. /*
  106. * Bind to the physical interface
  107. */
  108. memset (&s_addr, 0, sizeof (struct sockaddr_ll));
  109. s_addr.sll_family = AF_PACKET;
  110. s_addr.sll_protocol = htons (ETH_P_ALL);
  111. s_addr.sll_ifindex = circuit->interface->ifindex;
  112. if (bind (fd, (struct sockaddr *) (&s_addr),
  113. sizeof (struct sockaddr_ll)) < 0)
  114. {
  115. zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno));
  116. close (fd);
  117. return ISIS_WARNING;
  118. }
  119. circuit->fd = fd;
  120. if (if_is_broadcast (circuit->interface))
  121. {
  122. /*
  123. * Join to multicast groups
  124. * according to
  125. * 8.4.2 - Broadcast subnetwork IIH PDUs
  126. * FIXME: is there a case only one will fail??
  127. */
  128. /* joining ALL_L1_ISS */
  129. retval |= isis_multicast_join (circuit->fd, 1,
  130. circuit->interface->ifindex);
  131. /* joining ALL_L2_ISS */
  132. retval |= isis_multicast_join (circuit->fd, 2,
  133. circuit->interface->ifindex);
  134. /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */
  135. retval |= isis_multicast_join (circuit->fd, 3,
  136. circuit->interface->ifindex);
  137. }
  138. else
  139. {
  140. retval =
  141. isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
  142. }
  143. return retval;
  144. }
  145. /*
  146. * Create the socket and set the tx/rx funcs
  147. */
  148. int
  149. isis_sock_init (struct isis_circuit *circuit)
  150. {
  151. int retval = ISIS_OK;
  152. if (isisd_privs.change (ZPRIVS_RAISE))
  153. zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
  154. retval = open_packet_socket (circuit);
  155. if (retval != ISIS_OK)
  156. {
  157. zlog_warn ("%s: could not initialize the socket", __func__);
  158. goto end;
  159. }
  160. /* Assign Rx and Tx callbacks are based on real if type */
  161. if (if_is_broadcast (circuit->interface))
  162. {
  163. circuit->tx = isis_send_pdu_bcast;
  164. circuit->rx = isis_recv_pdu_bcast;
  165. }
  166. else if (if_is_pointopoint (circuit->interface))
  167. {
  168. circuit->tx = isis_send_pdu_p2p;
  169. circuit->rx = isis_recv_pdu_p2p;
  170. }
  171. else
  172. {
  173. zlog_warn ("isis_sock_init(): unknown circuit type");
  174. retval = ISIS_WARNING;
  175. goto end;
  176. }
  177. end:
  178. if (isisd_privs.change (ZPRIVS_LOWER))
  179. zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
  180. return retval;
  181. }
  182. static inline int
  183. llc_check (u_char * llc)
  184. {
  185. if (*llc != ISO_SAP || *(llc + 1) != ISO_SAP || *(llc + 2) != 3)
  186. return 0;
  187. return 1;
  188. }
  189. int
  190. isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
  191. {
  192. int bytesread, addr_len;
  193. struct sockaddr_ll s_addr;
  194. u_char llc[LLC_LEN];
  195. addr_len = sizeof (s_addr);
  196. memset (&s_addr, 0, sizeof (struct sockaddr_ll));
  197. bytesread = recvfrom (circuit->fd, (void *) &llc,
  198. LLC_LEN, MSG_PEEK,
  199. (struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
  200. if ((bytesread < 0) || (s_addr.sll_ifindex != (int)circuit->interface->ifindex))
  201. {
  202. if (bytesread < 0)
  203. {
  204. zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, "
  205. "bytesread %d, recvfrom(): %s",
  206. circuit->interface->name, circuit->fd, bytesread,
  207. safe_strerror (errno));
  208. }
  209. if (s_addr.sll_ifindex != (int)circuit->interface->ifindex)
  210. {
  211. zlog_warn("packet is received on multiple interfaces: "
  212. "socket interface %d, circuit interface %d, "
  213. "packet type %u",
  214. s_addr.sll_ifindex, circuit->interface->ifindex,
  215. s_addr.sll_pkttype);
  216. }
  217. /* get rid of the packet */
  218. bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
  219. MSG_DONTWAIT, (struct sockaddr *) &s_addr,
  220. (socklen_t *) &addr_len);
  221. return ISIS_WARNING;
  222. }
  223. /*
  224. * Filtering by llc field, discard packets sent by this host (other circuit)
  225. */
  226. if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
  227. {
  228. /* Read the packet into discard buff */
  229. bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
  230. MSG_DONTWAIT, (struct sockaddr *) &s_addr,
  231. (socklen_t *) &addr_len);
  232. if (bytesread < 0)
  233. zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
  234. return ISIS_WARNING;
  235. }
  236. /* on lan we have to read to the static buff first */
  237. bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT,
  238. (struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
  239. if (bytesread < 0)
  240. {
  241. zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
  242. return ISIS_WARNING;
  243. }
  244. /* then we lose the LLC */
  245. stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
  246. memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
  247. return ISIS_OK;
  248. }
  249. int
  250. isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
  251. {
  252. int bytesread, addr_len;
  253. struct sockaddr_ll s_addr;
  254. memset (&s_addr, 0, sizeof (struct sockaddr_ll));
  255. addr_len = sizeof (s_addr);
  256. /* we can read directly to the stream */
  257. bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd,
  258. circuit->interface->mtu, 0,
  259. (struct sockaddr *) &s_addr,
  260. (socklen_t *) &addr_len);
  261. if (s_addr.sll_pkttype == PACKET_OUTGOING)
  262. {
  263. /* Read the packet into discard buff */
  264. bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
  265. MSG_DONTWAIT, (struct sockaddr *) &s_addr,
  266. (socklen_t *) &addr_len);
  267. if (bytesread < 0)
  268. zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed");
  269. return ISIS_WARNING;
  270. }
  271. /* If we don't have protocol type 0x00FE which is
  272. * ISO over GRE we exit with pain :)
  273. */
  274. if (ntohs (s_addr.sll_protocol) != 0x00FE)
  275. {
  276. zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X",
  277. ntohs (s_addr.sll_protocol));
  278. return ISIS_WARNING;
  279. }
  280. memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
  281. return ISIS_OK;
  282. }
  283. int
  284. isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
  285. {
  286. struct msghdr msg;
  287. struct iovec iov[2];
  288. /* we need to do the LLC in here because of P2P circuits, which will
  289. * not need it
  290. */
  291. struct sockaddr_ll sa;
  292. stream_set_getp (circuit->snd_stream, 0);
  293. memset (&sa, 0, sizeof (struct sockaddr_ll));
  294. sa.sll_family = AF_PACKET;
  295. sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
  296. sa.sll_ifindex = circuit->interface->ifindex;
  297. sa.sll_halen = ETH_ALEN;
  298. /* RFC5309 section 4.1 recommends ALL_ISS */
  299. if (circuit->circ_type == CIRCUIT_T_P2P)
  300. memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN);
  301. else if (level == 1)
  302. memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
  303. else
  304. memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
  305. /* on a broadcast circuit */
  306. /* first we put the LLC in */
  307. sock_buff[0] = 0xFE;
  308. sock_buff[1] = 0xFE;
  309. sock_buff[2] = 0x03;
  310. memset (&msg, 0, sizeof (msg));
  311. msg.msg_name = &sa;
  312. msg.msg_namelen = sizeof (struct sockaddr_ll);
  313. msg.msg_iov = iov;
  314. msg.msg_iovlen = 2;
  315. iov[0].iov_base = sock_buff;
  316. iov[0].iov_len = LLC_LEN;
  317. iov[1].iov_base = circuit->snd_stream->data;
  318. iov[1].iov_len = stream_get_endp (circuit->snd_stream);
  319. if (sendmsg(circuit->fd, &msg, 0) < 0)
  320. {
  321. zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s",
  322. circuit->interface->name, safe_strerror(errno));
  323. if (ERRNO_IO_RETRY(errno))
  324. return ISIS_WARNING;
  325. return ISIS_ERROR;
  326. }
  327. return ISIS_OK;
  328. }
  329. int
  330. isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
  331. {
  332. struct sockaddr_ll sa;
  333. ssize_t rv;
  334. stream_set_getp (circuit->snd_stream, 0);
  335. memset (&sa, 0, sizeof (struct sockaddr_ll));
  336. sa.sll_family = AF_PACKET;
  337. sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
  338. sa.sll_ifindex = circuit->interface->ifindex;
  339. sa.sll_halen = ETH_ALEN;
  340. if (level == 1)
  341. memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
  342. else
  343. memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
  344. /* lets try correcting the protocol */
  345. sa.sll_protocol = htons (0x00FE);
  346. rv = sendto(circuit->fd, circuit->snd_stream->data,
  347. stream_get_endp (circuit->snd_stream), 0,
  348. (struct sockaddr *) &sa,
  349. sizeof (struct sockaddr_ll));
  350. if (rv < 0)
  351. {
  352. zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s",
  353. circuit->interface->name, safe_strerror(errno));
  354. if (ERRNO_IO_RETRY(errno))
  355. return ISIS_WARNING;
  356. return ISIS_ERROR;
  357. }
  358. return ISIS_OK;
  359. }
  360. #endif /* ISIS_METHOD == ISIS_METHOD_PFPACKET */