File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / irdp_packet.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

    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>