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