File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_pfpacket.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 5 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, 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 (circuit->circ_type == CIRCUIT_T_BROADCAST)
  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->circuit_is_type & IS_LEVEL_1)
  146: 	{
  147: 	  /* joining ALL_L1_ISS */
  148: 	  retval = isis_multicast_join (circuit->fd, 1,
  149: 					circuit->interface->ifindex);
  150: 	  /* joining ALL_ISS */
  151: 	  retval = isis_multicast_join (circuit->fd, 3,
  152: 					circuit->interface->ifindex);
  153: 	}
  154:       if (circuit->circuit_is_type & IS_LEVEL_2)
  155: 	/* joining ALL_L2_ISS */
  156: 	retval = isis_multicast_join (circuit->fd, 2,
  157: 				      circuit->interface->ifindex);
  158:     }
  159:   else
  160:     {
  161:       retval =
  162: 	isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
  163:     }
  164: 
  165:   return retval;
  166: }
  167: 
  168: /*
  169:  * Create the socket and set the tx/rx funcs
  170:  */
  171: int
  172: isis_sock_init (struct isis_circuit *circuit)
  173: {
  174:   int retval = ISIS_OK;
  175: 
  176:   if (isisd_privs.change (ZPRIVS_RAISE))
  177:     zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
  178: 
  179:   retval = open_packet_socket (circuit);
  180: 
  181:   if (retval != ISIS_OK)
  182:     {
  183:       zlog_warn ("%s: could not initialize the socket", __func__);
  184:       goto end;
  185:     }
  186: 
  187:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  188:     {
  189:       circuit->tx = isis_send_pdu_bcast;
  190:       circuit->rx = isis_recv_pdu_bcast;
  191:     }
  192:   else if (circuit->circ_type == CIRCUIT_T_P2P)
  193:     {
  194:       circuit->tx = isis_send_pdu_p2p;
  195:       circuit->rx = isis_recv_pdu_p2p;
  196:     }
  197:   else
  198:     {
  199:       zlog_warn ("isis_sock_init(): unknown circuit type");
  200:       retval = ISIS_WARNING;
  201:       goto end;
  202:     }
  203: 
  204: end:
  205:   if (isisd_privs.change (ZPRIVS_LOWER))
  206:     zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
  207: 
  208:   return retval;
  209: }
  210: 
  211: static inline int
  212: llc_check (u_char * llc)
  213: {
  214:   if (*llc != ISO_SAP || *(llc + 1) != ISO_SAP || *(llc + 2) != 3)
  215:     return 0;
  216: 
  217:   return 1;
  218: }
  219: 
  220: int
  221: isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
  222: {
  223:   int bytesread, addr_len;
  224:   struct sockaddr_ll s_addr;
  225:   u_char llc[LLC_LEN];
  226: 
  227:   addr_len = sizeof (s_addr);
  228: 
  229:   memset (&s_addr, 0, sizeof (struct sockaddr_ll));
  230: 
  231:   bytesread = recvfrom (circuit->fd, (void *) &llc,
  232: 			LLC_LEN, MSG_PEEK,
  233: 			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
  234: 
  235:   if (!circuit->area) {
  236:     return ISIS_OK;
  237:   }
  238: 
  239:   if (bytesread < 0)
  240:     {
  241:       zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
  242: 		 circuit->fd, safe_strerror (errno));
  243:       zlog_warn ("circuit is %s", circuit->interface->name);
  244:       zlog_warn ("circuit fd %d", circuit->fd);
  245:       zlog_warn ("bytesread %d", bytesread);
  246:       /* get rid of the packet */
  247:       bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
  248:       return ISIS_WARNING;
  249:     }
  250:   /*
  251:    * Filtering by llc field, discard packets sent by this host (other circuit)
  252:    */
  253:   if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
  254:     {
  255:       /*  Read the packet into discard buff */
  256:       bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
  257:       if (bytesread < 0)
  258: 	zlog_warn ("isis_recv_pdu_bcast(): read() failed");
  259:       return ISIS_WARNING;
  260:     }
  261: 
  262:   /* on lan we have to read to the static buff first */
  263:   bytesread = recvfrom (circuit->fd, sock_buff, circuit->interface->mtu, 0,
  264: 			(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
  265: 
  266:   /* then we lose the LLC */
  267:   stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
  268: 
  269:   memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
  270: 
  271:   return ISIS_OK;
  272: }
  273: 
  274: int
  275: isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
  276: {
  277:   int bytesread, addr_len;
  278:   struct sockaddr_ll s_addr;
  279: 
  280:   memset (&s_addr, 0, sizeof (struct sockaddr_ll));
  281:   addr_len = sizeof (s_addr);
  282: 
  283:   /* we can read directly to the stream */
  284:   bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd,
  285:                                circuit->interface->mtu, 0,
  286:                                (struct sockaddr *) &s_addr, 
  287:                                (socklen_t *) &addr_len);
  288: 
  289:   if (s_addr.sll_pkttype == PACKET_OUTGOING)
  290:     {
  291:       /*  Read the packet into discard buff */
  292:       bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
  293:       if (bytesread < 0)
  294: 	zlog_warn ("isis_recv_pdu_p2p(): read() failed");
  295:       return ISIS_WARNING;
  296:     }
  297: 
  298:   /* If we don't have protocol type 0x00FE which is
  299:    * ISO over GRE we exit with pain :)
  300:    */
  301:   if (ntohs (s_addr.sll_protocol) != 0x00FE)
  302:     {
  303:       zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X",
  304: 		 ntohs (s_addr.sll_protocol));
  305:       return ISIS_WARNING;
  306:     }
  307: 
  308:   memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
  309: 
  310:   return ISIS_OK;
  311: }
  312: 
  313: int
  314: isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
  315: {
  316:   /* we need to do the LLC in here because of P2P circuits, which will
  317:    * not need it
  318:    */
  319:   int written = 1;
  320:   struct sockaddr_ll sa;
  321: 
  322:   stream_set_getp (circuit->snd_stream, 0);
  323:   memset (&sa, 0, sizeof (struct sockaddr_ll));
  324:   sa.sll_family = AF_PACKET;
  325:   sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
  326:   sa.sll_ifindex = circuit->interface->ifindex;
  327:   sa.sll_halen = ETH_ALEN;
  328:   if (level == 1)
  329:     memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
  330:   else
  331:     memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
  332: 
  333:   /* on a broadcast circuit */
  334:   /* first we put the LLC in */
  335:   sock_buff[0] = 0xFE;
  336:   sock_buff[1] = 0xFE;
  337:   sock_buff[2] = 0x03;
  338: 
  339:   /* then we copy the data */
  340:   memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
  341: 	  stream_get_endp (circuit->snd_stream));
  342: 
  343:   /* now we can send this */
  344:   written = sendto (circuit->fd, sock_buff,
  345: 		    stream_get_endp(circuit->snd_stream) + LLC_LEN, 0,
  346: 		    (struct sockaddr *) &sa, sizeof (struct sockaddr_ll));
  347: 
  348:   return ISIS_OK;
  349: }
  350: 
  351: int
  352: isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
  353: {
  354: 
  355:   int written = 1;
  356:   struct sockaddr_ll sa;
  357: 
  358:   stream_set_getp (circuit->snd_stream, 0);
  359:   memset (&sa, 0, sizeof (struct sockaddr_ll));
  360:   sa.sll_family = AF_PACKET;
  361:   sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
  362:   sa.sll_ifindex = circuit->interface->ifindex;
  363:   sa.sll_halen = ETH_ALEN;
  364:   if (level == 1)
  365:     memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
  366:   else
  367:     memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
  368: 
  369: 
  370:   /* lets try correcting the protocol */
  371:   sa.sll_protocol = htons (0x00FE);
  372:   written = sendto (circuit->fd, circuit->snd_stream->data,
  373: 		    stream_get_endp (circuit->snd_stream), 0, 
  374: 		    (struct sockaddr *) &sa,
  375: 		    sizeof (struct sockaddr_ll));
  376: 
  377:   return ISIS_OK;
  378: }
  379: 
  380: #endif /* ISIS_METHOD == ISIS_METHOD_PFPACKET */

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