Annotation of embedaddon/quagga/zebra/irdp_packet.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *
                      3:  * Copyright (C) 2000  Robert Olsson.
                      4:  * Swedish University of Agricultural Sciences
                      5:  *
                      6:  * This file is part of GNU Zebra.
                      7:  *
                      8:  * GNU Zebra is free software; you can redistribute it and/or modify it
                      9:  * under the terms of the GNU General Public License as published by the
                     10:  * Free Software Foundation; either version 2, or (at your option) any
                     11:  * later version.
                     12:  *
                     13:  * GNU Zebra is distributed in the hope that it will be useful, but
                     14:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     16:  * General Public License for more details.
                     17:  *
                     18:  * You should have received a copy of the GNU General Public License
                     19:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
                     20:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
                     21:  * 02111-1307, USA.  
                     22:  */
                     23: 
                     24: /* 
                     25:  * This work includes work with the following copywrite:
                     26:  *
                     27:  * Copyright (C) 1997, 2000 Kunihiro Ishiguro
                     28:  *
                     29:  */
                     30: 
                     31: /* 
                     32:  * Thanks to Jens Låås at Swedish University of Agricultural Sciences
                     33:  * for reviewing and tests.
                     34:  */
                     35: 
                     36: 
                     37: #include <zebra.h>
                     38: 
                     39: 
                     40: #ifdef HAVE_IRDP
                     41: 
                     42: #include "if.h"
                     43: #include "vty.h"
                     44: #include "sockunion.h"
                     45: #include "prefix.h"
                     46: #include "command.h"
                     47: #include "memory.h"
                     48: #include "stream.h"
                     49: #include "ioctl.h"
                     50: #include "connected.h"
                     51: #include "log.h"
                     52: #include "zclient.h"
                     53: #include "thread.h"
                     54: #include "zebra/interface.h"
                     55: #include "zebra/rtadv.h"
                     56: #include "zebra/rib.h"
                     57: #include "zebra/zserv.h"
                     58: #include "zebra/redistribute.h"
                     59: #include "zebra/irdp.h"
                     60: #include <netinet/ip_icmp.h>
                     61: #include "if.h"
                     62: #include "checksum.h"
                     63: #include "sockunion.h"
                     64: #include "log.h"
                     65: #include "sockopt.h"
                     66: 
                     67: 
                     68: /* GLOBAL VARS */
                     69: 
                     70: int irdp_sock = -1;
                     71: 
                     72: extern struct zebra_t zebrad;
                     73: extern struct thread *t_irdp_raw;
                     74: 
                     75: static void
                     76: parse_irdp_packet(char *p, 
                     77:                  int len, 
                     78:                  struct interface *ifp)
                     79: {
                     80:   struct ip *ip = (struct ip *)p ;
                     81:   struct icmphdr *icmp;
                     82:   struct in_addr src;
                     83:   int ip_hlen, iplen, datalen;
                     84:   struct zebra_if *zi;
                     85:   struct irdp_interface *irdp;
                     86: 
                     87:   zi = ifp->info;
                     88:   if (!zi) 
                     89:     return;
                     90: 
                     91:   irdp = &zi->irdp;
                     92:   if (!irdp) 
                     93:     return;
                     94: 
                     95:   ip_hlen = ip->ip_hl << 2;
                     96:   
                     97:   sockopt_iphdrincl_swab_systoh (ip);
                     98:   
                     99:   iplen = ip->ip_len;
                    100:   datalen = len - ip_hlen;
                    101:   src = ip->ip_src;
                    102: 
                    103:   if (len != iplen)
                    104:     {
                    105:       zlog_err ("IRDP: RX length doesnt match IP length");
                    106:       return;
                    107:     }
                    108: 
                    109:   if (iplen < ICMP_MINLEN) 
                    110:     {
                    111:       zlog_err ("IRDP: RX ICMP packet too short from %s\n",
                    112:              inet_ntoa (src));
                    113:       return;
                    114:     }
                    115:     
                    116:   /* XXX: RAW doesnt receive link-layer, surely? ??? */
                    117:   /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
                    118:    len of IP-header) 14+20 */
                    119:   if (iplen > IRDP_RX_BUF-34) 
                    120:     {
                    121:       zlog_err ("IRDP: RX ICMP packet too long from %s\n",
                    122:                inet_ntoa (src));
                    123:       return;
                    124:     }
                    125: 
                    126:   icmp = (struct icmphdr *) (p+ip_hlen);
                    127: 
                    128:   /* check icmp checksum */    
                    129:   if (in_cksum (icmp, datalen) != icmp->checksum) 
                    130:     {
                    131:       zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
                    132:                  inet_ntoa (src));
                    133:       return;
                    134:     }
                    135:   
                    136:   /* Handle just only IRDP */
                    137:   if (!(icmp->type == ICMP_ROUTERADVERT
                    138:         || icmp->type == ICMP_ROUTERSOLICIT))
                    139:     return;
                    140:   
                    141:   if (icmp->code != 0) 
                    142:     {
                    143:       zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code,"
                    144:                  " silently ignored",
                    145:                  icmp->type, inet_ntoa (src));
                    146:       return;
                    147:     }
                    148: 
                    149:   if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST)
                    150:          && (irdp->flags & IF_BROADCAST))
                    151:         ||
                    152:         (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
                    153:          && !(irdp->flags & IF_BROADCAST)))
                    154:     {
                    155:       zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
                    156:                  inet_ntoa (src),
                    157:                  ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ?
                    158:                  "multicast" : inet_ntoa (ip->ip_dst),
                    159:                  ifp->name,
                    160:                  irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
                    161: 
                    162:       zlog_warn ("IRDP: Please correct settings\n");
                    163:       return;
                    164:     }
                    165: 
                    166:   switch (icmp->type) 
                    167:     {
                    168:     case ICMP_ROUTERADVERT:
                    169:       break;
                    170: 
                    171:     case ICMP_ROUTERSOLICIT:
                    172: 
                    173:       if(irdp->flags & IF_DEBUG_MESSAGES) 
                    174:        zlog_debug ("IRDP: RX Solicit on %s from %s\n",
                    175:                    ifp->name,
                    176:                    inet_ntoa (src));
                    177: 
                    178:       process_solicit(ifp);
                    179:       break;
                    180: 
                    181:     default:
                    182:       zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
                    183:                 icmp->type,
                    184:                 inet_ntoa (src));
                    185:     }
                    186: }
                    187: 
                    188: static int
                    189: irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex)
                    190: {
                    191:   struct msghdr msg;
                    192:   struct iovec iov;
                    193:   char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )];
                    194:   int ret;
                    195: 
                    196:   msg.msg_name = (void *)0;
                    197:   msg.msg_namelen = 0;
                    198:   msg.msg_iov = &iov;
                    199:   msg.msg_iovlen = 1;
                    200:   msg.msg_control = (void *) adata;
                    201:   msg.msg_controllen = sizeof adata;
                    202: 
                    203:   iov.iov_base = buf;
                    204:   iov.iov_len = size;
                    205: 
                    206:   ret = recvmsg (sock, &msg, 0);
                    207:   if (ret < 0) {
                    208:     zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno));
                    209:     return ret;
                    210:   }
                    211: 
                    212:   if (msg.msg_flags & MSG_TRUNC) {
                    213:     zlog_warn("IRDP: recvmsg: truncated message");
                    214:     return ret;
                    215:   }
                    216:   if (msg.msg_flags & MSG_CTRUNC) {
                    217:     zlog_warn("IRDP: recvmsg: truncated control message");
                    218:     return ret;
                    219:   }
                    220: 
                    221:   *ifindex = getsockopt_ifindex (AF_INET, &msg);
                    222: 
                    223:   return ret;
                    224: }
                    225: 
                    226: int irdp_read_raw(struct thread *r)
                    227: {
                    228:   struct interface *ifp;
                    229:   struct zebra_if *zi;
                    230:   struct irdp_interface *irdp;
                    231:   char buf[IRDP_RX_BUF];
                    232:   int ret, ifindex = 0;
                    233:   
                    234:   int irdp_sock = THREAD_FD (r);
                    235:   t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
                    236:   
                    237:   ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF,  &ifindex);
                    238:  
                    239:   if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
                    240: 
                    241:   ifp = if_lookup_by_index(ifindex);
                    242:   if(! ifp ) return ret;
                    243: 
                    244:   zi= ifp->info;
                    245:   if(! zi ) return ret;
                    246: 
                    247:   irdp = &zi->irdp;
                    248:   if(! irdp ) return ret;
                    249: 
                    250:   if(! (irdp->flags & IF_ACTIVE)) {
                    251: 
                    252:     if(irdp->flags & IF_DEBUG_MISC) 
                    253:       zlog_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name);
                    254:     return 0;
                    255:   }
                    256: 
                    257:   if(irdp->flags & IF_DEBUG_PACKET) {
                    258:     int i;
                    259:     zlog_debug("IRDP: RX (idx %d) ", ifindex);
                    260:     for(i=0; i < ret; i++) zlog_debug( "IRDP: RX %x ", buf[i]&0xFF);
                    261:   }
                    262: 
                    263:   parse_irdp_packet(buf, ret, ifp);
                    264: 
                    265:   return ret;
                    266: }
                    267: 
                    268: void 
                    269: send_packet(struct interface *ifp, 
                    270:            struct stream *s,
                    271:            u_int32_t dst,
                    272:            struct prefix *p,
                    273:            u_int32_t ttl)
                    274: {
                    275:   static struct sockaddr_in sockdst = {AF_INET};
                    276:   struct ip *ip;
                    277:   struct icmphdr *icmp;
                    278:   struct msghdr *msg;
                    279:   struct cmsghdr *cmsg;
                    280:   struct iovec iovector;
                    281:   char msgbuf[256];
                    282:   char buf[256];
                    283:   struct in_pktinfo *pktinfo;
                    284:   u_long src;
                    285:   int on;
                    286:  
                    287:   if (!(ifp->flags & IFF_UP))
                    288:     return;
                    289: 
                    290:   if (!p) 
                    291:     src = ntohl(p->u.prefix4.s_addr);
                    292:   else 
                    293:     src = 0; /* Is filled in */
                    294:   
                    295:   ip = (struct ip *) buf;
                    296:   ip->ip_hl = sizeof(struct ip) >> 2;
                    297:   ip->ip_v = IPVERSION;
                    298:   ip->ip_tos = 0xC0;
                    299:   ip->ip_off = 0L;
                    300:   ip->ip_p = 1;       /* IP_ICMP */
                    301:   ip->ip_ttl = ttl;
                    302:   ip->ip_src.s_addr = src;
                    303:   ip->ip_dst.s_addr = dst;
                    304:   icmp = (struct icmphdr *) (buf + sizeof (struct ip));
                    305: 
                    306:   /* Merge IP header with icmp packet */
                    307:   assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip)));
                    308:   stream_get(icmp, s, stream_get_endp(s));
                    309: 
                    310:   /* icmp->checksum is already calculated */
                    311:   ip->ip_len  = sizeof(struct ip) + stream_get_endp(s);
                    312: 
                    313:   on = 1;
                    314:   if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
                    315:                 (char *) &on, sizeof(on)) < 0)
                    316:     zlog_warn("sendto %s", safe_strerror (errno));
                    317: 
                    318: 
                    319:   if(dst == INADDR_BROADCAST ) {
                    320:     on = 1;
                    321:     if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
                    322:                   (char *) &on, sizeof(on)) < 0)
                    323:       zlog_warn("sendto %s", safe_strerror (errno));
                    324:   }
                    325: 
                    326:   if(dst !=  INADDR_BROADCAST) {
                    327:       on = 0; 
                    328:       if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP, 
                    329:                     (char *)&on,sizeof(on)) < 0)
                    330:        zlog_warn("sendto %s", safe_strerror (errno));
                    331:   }
                    332: 
                    333:   memset(&sockdst,0,sizeof(sockdst));
                    334:   sockdst.sin_family=AF_INET;
                    335:   sockdst.sin_addr.s_addr = dst;
                    336: 
                    337:   cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
                    338:   cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
                    339:   cmsg->cmsg_level = SOL_IP;
                    340:   cmsg->cmsg_type = IP_PKTINFO;
                    341:   pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
                    342:   pktinfo->ipi_ifindex = ifp->ifindex;
                    343:   pktinfo->ipi_spec_dst.s_addr = src;
                    344:   pktinfo->ipi_addr.s_addr = src;
                    345:  
                    346:   iovector.iov_base = (void *) buf;
                    347:   iovector.iov_len = ip->ip_len; 
                    348:   msg = (struct msghdr *) msgbuf;
                    349:   msg->msg_name = &sockdst;
                    350:   msg->msg_namelen = sizeof(sockdst);
                    351:   msg->msg_iov = &iovector;
                    352:   msg->msg_iovlen = 1;
                    353:   msg->msg_control = cmsg;
                    354:   msg->msg_controllen = cmsg->cmsg_len;
                    355:  
                    356:   sockopt_iphdrincl_swab_htosys (ip);
                    357:   
                    358:   if (sendmsg(irdp_sock, msg, 0) < 0) {
                    359:     zlog_warn("sendto %s", safe_strerror (errno));
                    360:   }
                    361:   /*   printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
                    362: }
                    363: 
                    364: 
                    365: #endif /* HAVE_IRDP */
                    366: 
                    367: 
                    368: 

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