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

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: 
                    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>