File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_pfpacket.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:22:28 2012 UTC (11 years, 9 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_21, HEAD
quagga

    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:       return ISIS_WARNING;
  133:     }
  134: 
  135:   circuit->fd = fd;
  136: 
  137:   if (if_is_broadcast (circuit->interface))
  138:     {
  139:       /*
  140:        * Join to multicast groups
  141:        * according to
  142:        * 8.4.2 - Broadcast subnetwork IIH PDUs
  143:        * FIXME: is there a case only one will fail??
  144:        */
  145:       if (circuit->is_type & IS_LEVEL_1)
  146:         /* joining ALL_L1_ISS */
  147:         retval = isis_multicast_join (circuit->fd, 1,
  148:                                       circuit->interface->ifindex);
  149:       if (circuit->is_type & IS_LEVEL_2)
  150:         /* joining ALL_L2_ISS */
  151:         retval = isis_multicast_join (circuit->fd, 2,
  152:                                       circuit->interface->ifindex);
  153:       /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */
  154:       retval = isis_multicast_join (circuit->fd, 3,
  155:                                     circuit->interface->ifindex);
  156:     }
  157:   else
  158:     {
  159:       retval =
  160:         isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
  161:     }
  162: 
  163:   return retval;
  164: }
  165: 
  166: /*
  167:  * Create the socket and set the tx/rx funcs
  168:  */
  169: int
  170: isis_sock_init (struct isis_circuit *circuit)
  171: {
  172:   int retval = ISIS_OK;
  173: 
  174:   if (isisd_privs.change (ZPRIVS_RAISE))
  175:     zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
  176: 
  177:   retval = open_packet_socket (circuit);
  178: 
  179:   if (retval != ISIS_OK)
  180:     {
  181:       zlog_warn ("%s: could not initialize the socket", __func__);
  182:       goto end;
  183:     }
  184: 
  185:   /* Assign Rx and Tx callbacks are based on real if type */
  186:   if (if_is_broadcast (circuit->interface))
  187:     {
  188:       circuit->tx = isis_send_pdu_bcast;
  189:       circuit->rx = isis_recv_pdu_bcast;
  190:     }
  191:   else if (if_is_pointopoint (circuit->interface))
  192:     {
  193:       circuit->tx = isis_send_pdu_p2p;
  194:       circuit->rx = isis_recv_pdu_p2p;
  195:     }
  196:   else
  197:     {
  198:       zlog_warn ("isis_sock_init(): unknown circuit type");
  199:       retval = ISIS_WARNING;
  200:       goto end;
  201:     }
  202: 
  203: end:
  204:   if (isisd_privs.change (ZPRIVS_LOWER))
  205:     zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
  206: 
  207:   return retval;
  208: }
  209: 
  210: static inline int
  211: llc_check (u_char * llc)
  212: {
  213:   if (*llc != ISO_SAP || *(llc + 1) != ISO_SAP || *(llc + 2) != 3)
  214:     return 0;
  215: 
  216:   return 1;
  217: }
  218: 
  219: int
  220: isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
  221: {
  222:   int bytesread, addr_len;
  223:   struct sockaddr_ll s_addr;
  224:   u_char llc[LLC_LEN];
  225: 
  226:   addr_len = sizeof (s_addr);
  227: 
  228:   memset (&s_addr, 0, sizeof (struct sockaddr_ll));
  229: 
  230:   bytesread = recvfrom (circuit->fd, (void *) &llc,
  231: 			LLC_LEN, MSG_PEEK,
  232: 			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
  233: 
  234:   if (bytesread < 0)
  235:     {
  236:       zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, "
  237:                  "recvfrom(): %s",
  238:                  circuit->interface->name, circuit->fd, bytesread,
  239:                  safe_strerror (errno));
  240:       /* get rid of the packet */
  241:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
  242:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
  243:                             (socklen_t *) &addr_len);
  244:       return ISIS_WARNING;
  245:     }
  246:   /*
  247:    * Filtering by llc field, discard packets sent by this host (other circuit)
  248:    */
  249:   if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
  250:     {
  251:       /*  Read the packet into discard buff */
  252:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
  253:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
  254:                             (socklen_t *) &addr_len);
  255:       if (bytesread < 0)
  256: 	zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
  257:       return ISIS_WARNING;
  258:     }
  259: 
  260:   /* on lan we have to read to the static buff first */
  261:   bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT,
  262: 			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
  263:   if (bytesread < 0)
  264:     {
  265:       zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
  266:       return ISIS_WARNING;
  267:     }
  268: 
  269:   /* then we lose the LLC */
  270:   stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
  271: 
  272:   memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
  273: 
  274:   return ISIS_OK;
  275: }
  276: 
  277: int
  278: isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
  279: {
  280:   int bytesread, addr_len;
  281:   struct sockaddr_ll s_addr;
  282: 
  283:   memset (&s_addr, 0, sizeof (struct sockaddr_ll));
  284:   addr_len = sizeof (s_addr);
  285: 
  286:   /* we can read directly to the stream */
  287:   bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd,
  288:                                circuit->interface->mtu, 0,
  289:                                (struct sockaddr *) &s_addr, 
  290:                                (socklen_t *) &addr_len);
  291: 
  292:   if (s_addr.sll_pkttype == PACKET_OUTGOING)
  293:     {
  294:       /*  Read the packet into discard buff */
  295:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
  296:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
  297:                             (socklen_t *) &addr_len);
  298:       if (bytesread < 0)
  299: 	zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed");
  300:       return ISIS_WARNING;
  301:     }
  302: 
  303:   /* If we don't have protocol type 0x00FE which is
  304:    * ISO over GRE we exit with pain :)
  305:    */
  306:   if (ntohs (s_addr.sll_protocol) != 0x00FE)
  307:     {
  308:       zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X",
  309: 		 ntohs (s_addr.sll_protocol));
  310:       return ISIS_WARNING;
  311:     }
  312: 
  313:   memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
  314: 
  315:   return ISIS_OK;
  316: }
  317: 
  318: int
  319: isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
  320: {
  321:   struct msghdr msg;
  322:   struct iovec iov[2];
  323: 
  324:   /* we need to do the LLC in here because of P2P circuits, which will
  325:    * not need it
  326:    */
  327:   int written = 1;
  328:   struct sockaddr_ll sa;
  329: 
  330:   stream_set_getp (circuit->snd_stream, 0);
  331:   memset (&sa, 0, sizeof (struct sockaddr_ll));
  332:   sa.sll_family = AF_PACKET;
  333:   sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
  334:   sa.sll_ifindex = circuit->interface->ifindex;
  335:   sa.sll_halen = ETH_ALEN;
  336:   /* RFC5309 section 4.1 recommends ALL_ISS */
  337:   if (circuit->circ_type == CIRCUIT_T_P2P)
  338:     memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN);
  339:   else if (level == 1)
  340:     memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
  341:   else
  342:     memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
  343: 
  344:   /* on a broadcast circuit */
  345:   /* first we put the LLC in */
  346:   sock_buff[0] = 0xFE;
  347:   sock_buff[1] = 0xFE;
  348:   sock_buff[2] = 0x03;
  349: 
  350:   memset (&msg, 0, sizeof (msg));
  351:   msg.msg_name = &sa;
  352:   msg.msg_namelen = sizeof (struct sockaddr_ll);
  353:   msg.msg_iov = iov;
  354:   msg.msg_iovlen = 2;
  355:   iov[0].iov_base = sock_buff;
  356:   iov[0].iov_len = LLC_LEN;
  357:   iov[1].iov_base = circuit->snd_stream->data;
  358:   iov[1].iov_len = stream_get_endp (circuit->snd_stream);
  359: 
  360:   written = sendmsg (circuit->fd, &msg, 0);
  361: 
  362:   return ISIS_OK;
  363: }
  364: 
  365: int
  366: isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
  367: {
  368:   int written = 1;
  369:   struct sockaddr_ll sa;
  370: 
  371:   stream_set_getp (circuit->snd_stream, 0);
  372:   memset (&sa, 0, sizeof (struct sockaddr_ll));
  373:   sa.sll_family = AF_PACKET;
  374:   sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
  375:   sa.sll_ifindex = circuit->interface->ifindex;
  376:   sa.sll_halen = ETH_ALEN;
  377:   if (level == 1)
  378:     memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
  379:   else
  380:     memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
  381: 
  382: 
  383:   /* lets try correcting the protocol */
  384:   sa.sll_protocol = htons (0x00FE);
  385:   written = sendto (circuit->fd, circuit->snd_stream->data,
  386: 		    stream_get_endp (circuit->snd_stream), 0, 
  387: 		    (struct sockaddr *) &sa,
  388: 		    sizeof (struct sockaddr_ll));
  389: 
  390:   return ISIS_OK;
  391: }
  392: 
  393: #endif /* ISIS_METHOD == ISIS_METHOD_PFPACKET */

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