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

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"
1.1.1.4 ! misho      29: #include "network.h"
1.1       misho      30: #include "stream.h"
                     31: #include "if.h"
                     32: 
                     33: #include "isisd/dict.h"
                     34: #include "isisd/include-netbsd/iso.h"
                     35: #include "isisd/isis_constants.h"
                     36: #include "isisd/isis_common.h"
                     37: #include "isisd/isis_circuit.h"
                     38: #include "isisd/isis_flags.h"
                     39: #include "isisd/isisd.h"
                     40: #include "isisd/isis_constants.h"
                     41: #include "isisd/isis_circuit.h"
                     42: #include "isisd/isis_network.h"
                     43: 
                     44: #include "privs.h"
                     45: 
                     46: extern struct zebra_privs_t isisd_privs;
                     47: 
                     48: /*
                     49:  * Table 9 - Architectural constants for use with ISO 8802 subnetworks
                     50:  * ISO 10589 - 8.4.8
                     51:  */
                     52: 
                     53: u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
                     54: u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
                     55: u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
                     56: u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
                     57: 
1.1.1.4 ! misho      58: static uint8_t discard_buff[8192];
        !            59: static uint8_t sock_buff[8192];
1.1       misho      60: 
                     61: /*
                     62:  * if level is 0 we are joining p2p multicast
                     63:  * FIXME: and the p2p multicast being ???
                     64:  */
                     65: static int
                     66: isis_multicast_join (int fd, int registerto, int if_num)
                     67: {
                     68:   struct packet_mreq mreq;
                     69: 
                     70:   memset (&mreq, 0, sizeof (mreq));
                     71:   mreq.mr_ifindex = if_num;
                     72:   if (registerto)
                     73:     {
                     74:       mreq.mr_type = PACKET_MR_MULTICAST;
                     75:       mreq.mr_alen = ETH_ALEN;
                     76:       if (registerto == 1)
                     77:        memcpy (&mreq.mr_address, ALL_L1_ISS, ETH_ALEN);
                     78:       else if (registerto == 2)
                     79:        memcpy (&mreq.mr_address, ALL_L2_ISS, ETH_ALEN);
                     80:       else if (registerto == 3)
                     81:        memcpy (&mreq.mr_address, ALL_ISS, ETH_ALEN);
                     82:       else
                     83:        memcpy (&mreq.mr_address, ALL_ESS, ETH_ALEN);
                     84: 
                     85:     }
                     86:   else
                     87:     {
                     88:       mreq.mr_type = PACKET_MR_ALLMULTI;
                     89:     }
                     90: #ifdef EXTREME_DEBUG
                     91:   zlog_debug ("isis_multicast_join(): fd=%d, reg_to=%d, if_num=%d, "
                     92:              "address = %02x:%02x:%02x:%02x:%02x:%02x",
                     93:              fd, registerto, if_num, mreq.mr_address[0], mreq.mr_address[1],
                     94:              mreq.mr_address[2], mreq.mr_address[3], mreq.mr_address[4],
                     95:              mreq.mr_address[5]);
                     96: #endif /* EXTREME_DEBUG */
                     97:   if (setsockopt (fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
                     98:                  sizeof (struct packet_mreq)))
                     99:     {
                    100:       zlog_warn ("isis_multicast_join(): setsockopt(): %s", safe_strerror (errno));
                    101:       return ISIS_WARNING;
                    102:     }
                    103: 
                    104:   return ISIS_OK;
                    105: }
                    106: 
                    107: static int
                    108: open_packet_socket (struct isis_circuit *circuit)
                    109: {
                    110:   struct sockaddr_ll s_addr;
                    111:   int fd, retval = ISIS_OK;
                    112: 
                    113:   fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
                    114:   if (fd < 0)
                    115:     {
                    116:       zlog_warn ("open_packet_socket(): socket() failed %s",
                    117:                 safe_strerror (errno));
                    118:       return ISIS_WARNING;
                    119:     }
                    120: 
                    121:   /*
                    122:    * Bind to the physical interface
                    123:    */
                    124:   memset (&s_addr, 0, sizeof (struct sockaddr_ll));
                    125:   s_addr.sll_family = AF_PACKET;
                    126:   s_addr.sll_protocol = htons (ETH_P_ALL);
                    127:   s_addr.sll_ifindex = circuit->interface->ifindex;
                    128: 
                    129:   if (bind (fd, (struct sockaddr *) (&s_addr),
                    130:            sizeof (struct sockaddr_ll)) < 0)
                    131:     {
                    132:       zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno));
1.1.1.3   misho     133:       close (fd);
1.1       misho     134:       return ISIS_WARNING;
                    135:     }
                    136: 
                    137:   circuit->fd = fd;
                    138: 
1.1.1.2   misho     139:   if (if_is_broadcast (circuit->interface))
1.1       misho     140:     {
                    141:       /*
                    142:        * Join to multicast groups
                    143:        * according to
                    144:        * 8.4.2 - Broadcast subnetwork IIH PDUs
                    145:        * FIXME: is there a case only one will fail??
                    146:        */
1.1.1.3   misho     147:       /* joining ALL_L1_ISS */
                    148:       retval |= isis_multicast_join (circuit->fd, 1,
1.1.1.2   misho     149:                                       circuit->interface->ifindex);
1.1.1.3   misho     150:       /* joining ALL_L2_ISS */
                    151:       retval |= isis_multicast_join (circuit->fd, 2,
1.1.1.2   misho     152:                                       circuit->interface->ifindex);
                    153:       /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */
1.1.1.3   misho     154:       retval |= isis_multicast_join (circuit->fd, 3,
1.1.1.2   misho     155:                                     circuit->interface->ifindex);
1.1       misho     156:     }
                    157:   else
                    158:     {
                    159:       retval =
1.1.1.2   misho     160:         isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
1.1       misho     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: 
1.1.1.2   misho     185:   /* Assign Rx and Tx callbacks are based on real if type */
                    186:   if (if_is_broadcast (circuit->interface))
1.1       misho     187:     {
                    188:       circuit->tx = isis_send_pdu_bcast;
                    189:       circuit->rx = isis_recv_pdu_bcast;
                    190:     }
1.1.1.2   misho     191:   else if (if_is_pointopoint (circuit->interface))
1.1       misho     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: 
1.1.1.4 ! misho     234:   if ((bytesread < 0) || (s_addr.sll_ifindex != (int)circuit->interface->ifindex))
1.1       misho     235:     {
1.1.1.4 ! misho     236:       if (bytesread < 0)
        !           237:         {
        !           238:           zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, "
        !           239:                      "bytesread %d, recvfrom(): %s",
        !           240:                      circuit->interface->name, circuit->fd, bytesread,
        !           241:                      safe_strerror (errno));
        !           242:         }
        !           243:       if (s_addr.sll_ifindex != (int)circuit->interface->ifindex)
        !           244:         {
        !           245:           zlog_warn("packet is received on multiple interfaces: "
        !           246:                     "socket interface %d, circuit interface %d, "
        !           247:                     "packet type %u",
        !           248:                     s_addr.sll_ifindex, circuit->interface->ifindex,
        !           249:                     s_addr.sll_pkttype);
        !           250:         }
        !           251: 
1.1       misho     252:       /* get rid of the packet */
1.1.1.2   misho     253:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
                    254:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
                    255:                             (socklen_t *) &addr_len);
1.1       misho     256:       return ISIS_WARNING;
                    257:     }
                    258:   /*
                    259:    * Filtering by llc field, discard packets sent by this host (other circuit)
                    260:    */
                    261:   if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
                    262:     {
                    263:       /*  Read the packet into discard buff */
1.1.1.2   misho     264:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
                    265:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
                    266:                             (socklen_t *) &addr_len);
1.1       misho     267:       if (bytesread < 0)
1.1.1.2   misho     268:        zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
1.1       misho     269:       return ISIS_WARNING;
                    270:     }
                    271: 
                    272:   /* on lan we have to read to the static buff first */
1.1.1.2   misho     273:   bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT,
1.1       misho     274:                        (struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
1.1.1.2   misho     275:   if (bytesread < 0)
                    276:     {
                    277:       zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
                    278:       return ISIS_WARNING;
                    279:     }
1.1       misho     280: 
                    281:   /* then we lose the LLC */
                    282:   stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
                    283: 
                    284:   memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
                    285: 
                    286:   return ISIS_OK;
                    287: }
                    288: 
                    289: int
                    290: isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
                    291: {
                    292:   int bytesread, addr_len;
                    293:   struct sockaddr_ll s_addr;
                    294: 
                    295:   memset (&s_addr, 0, sizeof (struct sockaddr_ll));
                    296:   addr_len = sizeof (s_addr);
                    297: 
                    298:   /* we can read directly to the stream */
                    299:   bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd,
                    300:                                circuit->interface->mtu, 0,
                    301:                                (struct sockaddr *) &s_addr, 
                    302:                                (socklen_t *) &addr_len);
                    303: 
                    304:   if (s_addr.sll_pkttype == PACKET_OUTGOING)
                    305:     {
                    306:       /*  Read the packet into discard buff */
1.1.1.2   misho     307:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
                    308:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
                    309:                             (socklen_t *) &addr_len);
1.1       misho     310:       if (bytesread < 0)
1.1.1.2   misho     311:        zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed");
1.1       misho     312:       return ISIS_WARNING;
                    313:     }
                    314: 
                    315:   /* If we don't have protocol type 0x00FE which is
                    316:    * ISO over GRE we exit with pain :)
                    317:    */
                    318:   if (ntohs (s_addr.sll_protocol) != 0x00FE)
                    319:     {
                    320:       zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X",
                    321:                 ntohs (s_addr.sll_protocol));
                    322:       return ISIS_WARNING;
                    323:     }
                    324: 
                    325:   memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
                    326: 
                    327:   return ISIS_OK;
                    328: }
                    329: 
                    330: int
                    331: isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
                    332: {
1.1.1.2   misho     333:   struct msghdr msg;
                    334:   struct iovec iov[2];
                    335: 
1.1       misho     336:   /* we need to do the LLC in here because of P2P circuits, which will
                    337:    * not need it
                    338:    */
                    339:   struct sockaddr_ll sa;
                    340: 
                    341:   stream_set_getp (circuit->snd_stream, 0);
                    342:   memset (&sa, 0, sizeof (struct sockaddr_ll));
                    343:   sa.sll_family = AF_PACKET;
                    344:   sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
                    345:   sa.sll_ifindex = circuit->interface->ifindex;
                    346:   sa.sll_halen = ETH_ALEN;
1.1.1.2   misho     347:   /* RFC5309 section 4.1 recommends ALL_ISS */
                    348:   if (circuit->circ_type == CIRCUIT_T_P2P)
                    349:     memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN);
                    350:   else if (level == 1)
1.1       misho     351:     memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
                    352:   else
                    353:     memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
                    354: 
                    355:   /* on a broadcast circuit */
                    356:   /* first we put the LLC in */
                    357:   sock_buff[0] = 0xFE;
                    358:   sock_buff[1] = 0xFE;
                    359:   sock_buff[2] = 0x03;
                    360: 
1.1.1.2   misho     361:   memset (&msg, 0, sizeof (msg));
                    362:   msg.msg_name = &sa;
                    363:   msg.msg_namelen = sizeof (struct sockaddr_ll);
                    364:   msg.msg_iov = iov;
                    365:   msg.msg_iovlen = 2;
                    366:   iov[0].iov_base = sock_buff;
                    367:   iov[0].iov_len = LLC_LEN;
                    368:   iov[1].iov_base = circuit->snd_stream->data;
                    369:   iov[1].iov_len = stream_get_endp (circuit->snd_stream);
                    370: 
1.1.1.4 ! misho     371:   if (sendmsg(circuit->fd, &msg, 0) < 0)
        !           372:     {
        !           373:       zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s",
        !           374:                 circuit->interface->name, safe_strerror(errno));
        !           375:       if (ERRNO_IO_RETRY(errno))
        !           376:         return ISIS_WARNING;
        !           377:       return ISIS_ERROR;
        !           378:     }
1.1       misho     379:   return ISIS_OK;
                    380: }
                    381: 
                    382: int
                    383: isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
                    384: {
                    385:   struct sockaddr_ll sa;
1.1.1.4 ! misho     386:   ssize_t rv;
1.1       misho     387: 
                    388:   stream_set_getp (circuit->snd_stream, 0);
                    389:   memset (&sa, 0, sizeof (struct sockaddr_ll));
                    390:   sa.sll_family = AF_PACKET;
                    391:   sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
                    392:   sa.sll_ifindex = circuit->interface->ifindex;
                    393:   sa.sll_halen = ETH_ALEN;
                    394:   if (level == 1)
                    395:     memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
                    396:   else
                    397:     memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
                    398: 
                    399: 
                    400:   /* lets try correcting the protocol */
                    401:   sa.sll_protocol = htons (0x00FE);
1.1.1.4 ! misho     402:   rv = sendto(circuit->fd, circuit->snd_stream->data,
        !           403:              stream_get_endp (circuit->snd_stream), 0,
        !           404:              (struct sockaddr *) &sa,
        !           405:              sizeof (struct sockaddr_ll));
        !           406:   if (rv < 0)
        !           407:     {
        !           408:       zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s",
        !           409:                 circuit->interface->name, safe_strerror(errno));
        !           410:       if (ERRNO_IO_RETRY(errno))
        !           411:         return ISIS_WARNING;
        !           412:       return ISIS_ERROR;
        !           413:     }
1.1       misho     414:   return ISIS_OK;
                    415: }
                    416: 
                    417: #endif /* ISIS_METHOD == ISIS_METHOD_PFPACKET */

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