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

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));
                    132:       return ISIS_WARNING;
                    133:     }
                    134: 
                    135:   circuit->fd = fd;
                    136: 
1.1.1.2 ! misho     137:   if (if_is_broadcast (circuit->interface))
1.1       misho     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:        */
1.1.1.2 ! misho     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);
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: 
                    234:   if (bytesread < 0)
                    235:     {
1.1.1.2 ! misho     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));
1.1       misho     240:       /* get rid of the packet */
1.1.1.2 ! misho     241:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
        !           242:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
        !           243:                             (socklen_t *) &addr_len);
1.1       misho     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 */
1.1.1.2 ! misho     252:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
        !           253:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
        !           254:                             (socklen_t *) &addr_len);
1.1       misho     255:       if (bytesread < 0)
1.1.1.2 ! misho     256:        zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
1.1       misho     257:       return ISIS_WARNING;
                    258:     }
                    259: 
                    260:   /* on lan we have to read to the static buff first */
1.1.1.2 ! misho     261:   bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT,
1.1       misho     262:                        (struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
1.1.1.2 ! misho     263:   if (bytesread < 0)
        !           264:     {
        !           265:       zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
        !           266:       return ISIS_WARNING;
        !           267:     }
1.1       misho     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 */
1.1.1.2 ! misho     295:       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
        !           296:                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
        !           297:                             (socklen_t *) &addr_len);
1.1       misho     298:       if (bytesread < 0)
1.1.1.2 ! misho     299:        zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed");
1.1       misho     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: {
1.1.1.2 ! misho     321:   struct msghdr msg;
        !           322:   struct iovec iov[2];
        !           323: 
1.1       misho     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;
1.1.1.2 ! misho     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)
1.1       misho     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: 
1.1.1.2 ! misho     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);
1.1       misho     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>