irdp_packet.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:8k
源码类别:

网络

开发平台:

Unix_Linux

  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.  * This work includes work with the following copywrite:
  25.  *
  26.  * Copyright (C) 1997, 2000 Kunihiro Ishiguro
  27.  *
  28.  */
  29. /* 
  30.  * Thanks to Jens L邋s at Swedish University of Agricultural Sciences
  31.  * for reviewing and tests.
  32.  */
  33. #include <zebra.h>
  34. #ifdef HAVE_IRDP
  35. #include "if.h"
  36. #include "vty.h"
  37. #include "sockunion.h"
  38. #include "prefix.h"
  39. #include "command.h"
  40. #include "memory.h"
  41. #include "stream.h"
  42. #include "ioctl.h"
  43. #include "connected.h"
  44. #include "log.h"
  45. #include "zclient.h"
  46. #include "thread.h"
  47. #include "zebra/interface.h"
  48. #include "zebra/rtadv.h"
  49. #include "zebra/rib.h"
  50. #include "zebra/zserv.h"
  51. #include "zebra/redistribute.h"
  52. #include "zebra/irdp.h"
  53. #include <netinet/ip_icmp.h>
  54. #include "if.h"
  55. #include "sockunion.h"
  56. #include "log.h"
  57. /* GLOBAL VARS */
  58. int irdp_sock;
  59. char b1[16], b2[16], b3[16], b4[16];  /* For inet_2a */
  60. extern struct thread_master *master;
  61. extern struct thread *t_irdp_raw;
  62. extern struct interface *get_iflist_ifp(int idx);
  63. int in_cksum (void *ptr, int nbytes);
  64. void process_solicit (struct interface *ifp);
  65. void parse_irdp_packet(char *p, 
  66.   int len, 
  67.   struct interface *ifp)
  68. {
  69.   struct ip *ip = (struct ip *)p ;
  70.   struct icmphdr *icmp;
  71.   struct in_addr src;
  72.   int ip_hlen, ip_len;
  73.   struct zebra_if *zi;
  74.   struct irdp_interface *irdp;
  75.   zi = ifp->info;
  76.   if(!zi) return;
  77.   irdp = &zi->irdp;
  78.   if(!irdp) return;
  79.   ip_hlen = ip->ip_hl*4; 
  80.   ip_len = ntohs(ip->ip_len);
  81.   len = len - ip_hlen;
  82.   src = ip->ip_src;
  83.   if(ip_len < ICMP_MINLEN) {
  84.     zlog_err ("IRDP: RX ICMP packet too short from %sn",
  85.       inet_ntoa (src));
  86.     return;
  87.   }
  88.   /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
  89.    len of IP-header) 14+20 */
  90.   if(ip_len > IRDP_RX_BUF-34) {
  91.     zlog_err ("IRDP: RX ICMP packet too long from %sn",
  92.       inet_ntoa (src));
  93.     return;
  94.   }
  95.   if (in_cksum (ip, ip_len)) {
  96.     zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
  97.        inet_ntoa (src));
  98.     return;
  99.   }
  100.   icmp = (struct icmphdr *) (p+ip_hlen);
  101.   /* Handle just only IRDP */
  102.   if( icmp->type == ICMP_ROUTERADVERT);
  103.   else if( icmp->type == ICMP_ROUTERSOLICIT);
  104.   else return;
  105.  
  106.   if (icmp->code != 0) {
  107.     zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code, silently ignored",
  108.        icmp->type,
  109.        inet_ntoa (src));
  110.     return;
  111.   }
  112.   if(ip->ip_dst.s_addr == INADDR_BROADCAST && 
  113.      irdp->flags & IF_BROADCAST);
  114.   else if ( ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP && 
  115.     ! (irdp->flags &  IF_BROADCAST));
  116.   else { /* ERROR */
  117.     zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %sn",
  118.        inet_ntoa (src), 
  119.        ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP? 
  120.        "multicast" : inet_ntoa(ip->ip_dst),
  121.        ifp->name,
  122.        irdp->flags &  IF_BROADCAST? 
  123.        "broadcast" : "multicast");
  124.     zlog_warn ("IRDP: Please correct settingsn");
  125.     return;
  126.   }
  127.   switch (icmp->type) 
  128.     {
  129.     case ICMP_ROUTERADVERT:
  130.       break;
  131.     case ICMP_ROUTERSOLICIT:
  132.       if(irdp->flags & IF_DEBUG_MESSAGES) 
  133. zlog_warn ("IRDP: RX Solicit on %s from %sn",
  134.    ifp->name,
  135.    inet_ntoa (src));
  136.       process_solicit(ifp);
  137.       break;
  138.     default:
  139.       zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
  140.  icmp->type,
  141.  inet_ntoa (src));
  142.     }
  143. }
  144. int irdp_recvmsg (int sock, 
  145.       u_char *buf, 
  146.       int size, 
  147.       int *ifindex)
  148. {
  149.   struct msghdr msg;
  150.   struct iovec iov;
  151.   struct cmsghdr *ptr;
  152.   char adata[1024];
  153.   int ret;
  154.   msg.msg_name = (void *)0;
  155.   msg.msg_namelen = 0;
  156.   msg.msg_iov = &iov;
  157.   msg.msg_iovlen = 1;
  158.   msg.msg_control = (void *) adata;
  159.   msg.msg_controllen = sizeof adata;
  160.   iov.iov_base = buf;
  161.   iov.iov_len = size;
  162.   ret = recvmsg (sock, &msg, 0);
  163.   if (ret < 0) {
  164.     zlog_warn("IRDP: recvmsg: read error %s", strerror(errno));
  165.     return ret;
  166.   }
  167.   if (msg.msg_flags & MSG_TRUNC) {
  168.     zlog_warn("IRDP: recvmsg: truncated message");
  169.     return ret;
  170.   }
  171.   if (msg.msg_flags & MSG_CTRUNC) {
  172.     zlog_warn("IRDP: recvmsg: truncated control message");
  173.     return ret;
  174.   }
  175.   for (ptr = CMSG_FIRSTHDR(&msg); ptr ; ptr = CMSG_NXTHDR(&msg, ptr))
  176.     if (ptr->cmsg_level == SOL_IP && ptr->cmsg_type == IP_PKTINFO) 
  177.       {
  178.         struct in_pktinfo *pktinfo;
  179.            pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
  180.         *ifindex = pktinfo->ipi_ifindex;
  181.       }
  182.   return ret;
  183. }
  184. int irdp_read_raw(struct thread *r)
  185. {
  186.   struct interface *ifp;
  187.   struct zebra_if *zi;
  188.   struct irdp_interface *irdp;
  189.   char buf[IRDP_RX_BUF];
  190.   int ret, ifindex;
  191.   
  192.   int irdp_sock = THREAD_FD (r);
  193.   t_irdp_raw = thread_add_read (master, irdp_read_raw, NULL, irdp_sock);
  194.   
  195.   ret = irdp_recvmsg (irdp_sock, buf, IRDP_RX_BUF,  &ifindex);
  196.  
  197.   if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
  198.   ifp = get_iflist_ifp(ifindex);
  199.   if(! ifp ) return ret;
  200.   zi= ifp->info;
  201.   if(! zi ) return ret;
  202.   irdp = &zi->irdp;
  203.   if(! irdp ) return ret;
  204.   if(! (irdp->flags & IF_ACTIVE)) {
  205.     if(irdp->flags & IF_DEBUG_MISC) 
  206.       zlog_warn("IRDP: RX ICMP for disabled interface %sn",
  207. ifp->name);
  208.     return 0;
  209.   }
  210.   if(irdp->flags & IF_DEBUG_PACKET) {
  211.     int i;
  212.     zlog_warn("IRDP: RX (idx %d) ", ifindex);
  213.     for(i=0; i < ret; i++) zlog_warn( "IRDP: RX %x ", buf[i]&0xFF);
  214.   }
  215.   parse_irdp_packet(buf, ret, ifp);
  216.   return ret;
  217. }
  218. void send_packet(struct interface *ifp, 
  219.     struct stream *s,
  220.     u_int32_t dst,
  221.     struct prefix *p,
  222.     u_int32_t ttl)
  223. {
  224.   static struct sockaddr_in sockdst = {AF_INET};
  225.   struct ip *ip;
  226.   struct icmphdr *icmp;
  227.   struct msghdr *msg;
  228.   struct cmsghdr *cmsg;
  229.   struct iovec iovector;
  230.   char msgbuf[256];
  231.   char buf[256];
  232.   struct in_pktinfo *pktinfo;
  233.   u_long src;
  234.   int on;
  235.  
  236.   if (! (ifp->flags & IFF_UP)) return;
  237.   if(!p) src = ntohl(p->u.prefix4.s_addr);
  238.   else src = 0; /* Is filled in */
  239.   
  240.   ip = (struct ip *) buf;
  241.   ip->ip_hl = sizeof(struct ip) >> 2;
  242.   ip->ip_v = IPVERSION;
  243.   ip->ip_tos = 0xC0;
  244.   ip->ip_off = 0L;
  245.   ip->ip_p = 1;       /* IP_ICMP */
  246.   ip->ip_ttl = ttl;
  247.   ip->ip_src.s_addr = src;
  248.   ip->ip_dst.s_addr = dst;
  249.   icmp = (struct icmphdr *) (buf + 20);
  250.   /* Merge IP header with icmp packet */
  251.   stream_get(icmp, s, s->putp);
  252.   /* icmp->checksum is already calculated */
  253.   ip->ip_len  = sizeof(struct ip) + s->putp;
  254.   stream_free(s); 
  255.   on = 1;
  256.   if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
  257.  (char *) &on, sizeof(on)) < 0)
  258.     zlog_warn("sendto %s", strerror (errno));
  259.   if(dst == INADDR_BROADCAST ) {
  260.     on = 1;
  261.     if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
  262.    (char *) &on, sizeof(on)) < 0)
  263.       zlog_warn("sendto %s", strerror (errno));
  264.   }
  265.   if(dst !=  INADDR_BROADCAST) {
  266.       on = 0; 
  267.       if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP, 
  268.      (char *)&on,sizeof(on)) < 0)
  269. zlog_warn("sendto %s", strerror (errno));
  270.   }
  271.   bzero(&sockdst,sizeof(sockdst));
  272.   sockdst.sin_family=AF_INET;
  273.   sockdst.sin_addr.s_addr = dst;
  274.   cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
  275.   cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
  276.   cmsg->cmsg_level = SOL_IP;
  277.   cmsg->cmsg_type = IP_PKTINFO;
  278.   pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
  279.   pktinfo->ipi_ifindex = ifp->ifindex;
  280.   pktinfo->ipi_spec_dst.s_addr = src;
  281.   pktinfo->ipi_addr.s_addr = src;
  282.  
  283.   iovector.iov_base = (void *) buf;
  284.   iovector.iov_len = ip->ip_len; 
  285.   msg = (struct msghdr *) msgbuf;
  286.   msg->msg_name = &sockdst;
  287.   msg->msg_namelen = sizeof(sockdst);
  288.   msg->msg_iov = &iovector;
  289.   msg->msg_iovlen = 1;
  290.   msg->msg_control = cmsg;
  291.   msg->msg_controllen = cmsg->cmsg_len;
  292.  
  293.   if (sendmsg(irdp_sock, msg, 0) < 0) {
  294.     zlog_warn("sendto %s", strerror (errno));
  295.   }
  296.   /*   printf("TX on %s idx %dn", ifp->name, ifp->ifindex); */
  297. }
  298. #endif /* HAVE_IRDP */