Annotation of embedaddon/quagga/isisd/isis_pfpacket.c, revision 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>