File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_pfpacket.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:38 2013 UTC (11 years ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>