Annotation of embedaddon/quagga/isisd/isis_pfpacket.c, revision 1.1.1.3

1.1       misho       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));
1.1.1.3 ! misho     132:       close (fd);
1.1       misho     133:       return ISIS_WARNING;
                    134:     }
                    135: 
                    136:   circuit->fd = fd;
                    137: 
1.1.1.2   misho     138:   if (if_is_broadcast (circuit->interface))
1.1       misho     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:        */
1.1.1.3 ! misho     146:       /* joining ALL_L1_ISS */
        !           147:       retval |= isis_multicast_join (circuit->fd, 1,
1.1.1.2   misho     148:                                       circuit->interface->ifindex);
1.1.1.3 ! misho     149:       /* joining ALL_L2_ISS */
        !           150:       retval |= isis_multicast_join (circuit->fd, 2,
1.1.1.2   misho     151:                                       circuit->interface->ifindex);
                    152:       /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */
1.1.1.3 ! misho     153:       retval |= isis_multicast_join (circuit->fd, 3,
1.1.1.2   misho     154:                                     circuit->interface->ifindex);
1.1       misho     155:     }
                    156:   else
                    157:     {
                    158:       retval =
1.1.1.2   misho     159:         isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
1.1       misho     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: 
1.1.1.2   misho     184:   /* Assign Rx and Tx callbacks are based on real if type */
                    185:   if (if_is_broadcast (circuit->interface))
1.1       misho     186:     {
                    187:       circuit->tx = isis_send_pdu_bcast;
                    188:       circuit->rx = isis_recv_pdu_bcast;
                    189:     }
1.1.1.2   misho     190:   else if (if_is_pointopoint (circuit->interface))
1.1       misho     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:     {
1.1.1.2   misho     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));
1.1       misho     239:       /* get rid of the packet */
1.1.1.2   misho     240:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
                    241:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
                    242:                             (socklen_t *) &addr_len);
1.1       misho     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 */
1.1.1.2   misho     251:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
                    252:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
                    253:                             (socklen_t *) &addr_len);
1.1       misho     254:       if (bytesread < 0)
1.1.1.2   misho     255:        zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
1.1       misho     256:       return ISIS_WARNING;
                    257:     }
                    258: 
                    259:   /* on lan we have to read to the static buff first */
1.1.1.2   misho     260:   bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT,
1.1       misho     261:                        (struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
1.1.1.2   misho     262:   if (bytesread < 0)
                    263:     {
                    264:       zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
                    265:       return ISIS_WARNING;
                    266:     }
1.1       misho     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 */
1.1.1.2   misho     294:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
                    295:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
                    296:                             (socklen_t *) &addr_len);
1.1       misho     297:       if (bytesread < 0)
1.1.1.2   misho     298:        zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed");
1.1       misho     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: {
1.1.1.2   misho     320:   struct msghdr msg;
                    321:   struct iovec iov[2];
                    322: 
1.1       misho     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;
1.1.1.2   misho     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)
1.1       misho     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: 
1.1.1.2   misho     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);
1.1       misho     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>