]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/irdp_packet.c
isisd: implement the 'lsp-too-large' notification
[mirror_frr.git] / zebra / irdp_packet.c
index 20982b31a1e790110b93b150e6e4cbd7ff011700..bebccd716820403b20c856e07e8f7da6ba0d75bc 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-/* 
+/*
  * This work includes work with the following copywrite:
  *
  * Copyright (C) 1997, 2000 Kunihiro Ishiguro
  *
  */
 
-/* 
- * Thanks to Jens Låås at Swedish University of Agricultural Sciences
+/*
+ * Thanks to Jens Laas at Swedish University of Agricultural Sciences
  * for reviewing and tests.
  */
 
 
 #include <zebra.h>
+#include <netinet/ip_icmp.h>
 
-
-#ifdef HAVE_IRDP
-
-#include "if.h"
-#include "vty.h"
-#include "sockunion.h"
-#include "prefix.h"
+#include "checksum.h"
 #include "command.h"
-#include "memory.h"
-#include "zebra_memory.h"
-#include "stream.h"
-#include "ioctl.h"
 #include "connected.h"
+#include "if.h"
+#include "ioctl.h"
 #include "log.h"
-#include "zclient.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "sockopt.h"
+#include "sockunion.h"
+#include "sockunion.h"
+#include "stream.h"
 #include "thread.h"
+#include "vty.h"
+#include "zclient.h"
+#include "lib_errors.h"
+
+#include "zebra_memory.h"
 #include "zebra/interface.h"
 #include "zebra/rtadv.h"
 #include "zebra/rib.h"
 #include "zebra/zserv.h"
 #include "zebra/redistribute.h"
 #include "zebra/irdp.h"
-#include <netinet/ip_icmp.h>
-#include "if.h"
-#include "checksum.h"
-#include "sockunion.h"
-#include "log.h"
-#include "sockopt.h"
+#include "zebra/zebra_errors.h"
 
 
 /* GLOBAL VARS */
@@ -71,294 +70,292 @@ int irdp_sock = -1;
 
 extern struct thread *t_irdp_raw;
 
-static void
-parse_irdp_packet(char *p, 
-                 int len, 
-                 struct interface *ifp)
+static void parse_irdp_packet(char *p, int len, struct interface *ifp)
 {
-  struct ip *ip = (struct ip *)p ;
-  struct icmphdr *icmp;
-  struct in_addr src;
-  int ip_hlen, iplen, datalen;
-  struct zebra_if *zi;
-  struct irdp_interface *irdp;
-
-  zi = ifp->info;
-  if (!zi) 
-    return;
-
-  irdp = &zi->irdp;
-  if (!irdp) 
-    return;
-
-  ip_hlen = ip->ip_hl << 2;
-  
-  sockopt_iphdrincl_swab_systoh (ip);
-  
-  iplen = ip->ip_len;
-  datalen = len - ip_hlen;
-  src = ip->ip_src;
-
-  if (len != iplen)
-    {
-      zlog_err ("IRDP: RX length doesnt match IP length");
-      return;
-    }
-
-  if (iplen < ICMP_MINLEN) 
-    {
-      zlog_err ("IRDP: RX ICMP packet too short from %s\n",
-             inet_ntoa (src));
-      return;
-    }
-    
-  /* XXX: RAW doesnt receive link-layer, surely? ??? */
-  /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
-   len of IP-header) 14+20 */
-  if (iplen > IRDP_RX_BUF-34) 
-    {
-      zlog_err ("IRDP: RX ICMP packet too long from %s\n",
-               inet_ntoa (src));
-      return;
-    }
-
-  icmp = (struct icmphdr *) (p+ip_hlen);
-
-  /* check icmp checksum */    
-  if (in_cksum (icmp, datalen) != icmp->checksum) 
-    {
-      zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
-                 inet_ntoa (src));
-      return;
-    }
-  
-  /* Handle just only IRDP */
-  if (!(icmp->type == ICMP_ROUTERADVERT
-        || icmp->type == ICMP_ROUTERSOLICIT))
-    return;
-  
-  if (icmp->code != 0) 
-    {
-      zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code,"
-                 " silently ignored",
-                 icmp->type, inet_ntoa (src));
-      return;
-    }
-
-  if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST)
-         && (irdp->flags & IF_BROADCAST))
-        ||
-        (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
-         && !(irdp->flags & IF_BROADCAST)))
-    {
-      zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
-                 inet_ntoa (src),
-                 ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ?
-                 "multicast" : inet_ntoa (ip->ip_dst),
-                 ifp->name,
-                 irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
-
-      zlog_warn ("IRDP: Please correct settings\n");
-      return;
-    }
-
-  switch (icmp->type) 
-    {
-    case ICMP_ROUTERADVERT:
-      break;
-
-    case ICMP_ROUTERSOLICIT:
-
-      if(irdp->flags & IF_DEBUG_MESSAGES) 
-       zlog_debug ("IRDP: RX Solicit on %s from %s\n",
-                   ifp->name,
-                   inet_ntoa (src));
-
-      process_solicit(ifp);
-      break;
-
-    default:
-      zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
-                icmp->type,
-                inet_ntoa (src));
-    }
+       struct ip *ip = (struct ip *)p;
+       struct icmphdr *icmp;
+       struct in_addr src;
+       int ip_hlen, iplen, datalen;
+       struct zebra_if *zi;
+       struct irdp_interface *irdp;
+
+       zi = ifp->info;
+       if (!zi)
+               return;
+
+       irdp = zi->irdp;
+       if (!irdp)
+               return;
+
+       ip_hlen = ip->ip_hl << 2;
+
+       sockopt_iphdrincl_swab_systoh(ip);
+
+       iplen = ip->ip_len;
+       datalen = len - ip_hlen;
+       src = ip->ip_src;
+
+       if (len != iplen) {
+               flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
+                        "IRDP: RX length doesn't match IP length");
+               return;
+       }
+
+       if (iplen < ICMP_MINLEN) {
+               flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
+                        "IRDP: RX ICMP packet too short from %s\n",
+                        inet_ntoa(src));
+               return;
+       }
+
+       /* XXX: RAW doesn't receive link-layer, surely? ??? */
+       /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen
+        +
+        len of IP-header) 14+20 */
+       if (iplen > IRDP_RX_BUF - 34) {
+               flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
+                        "IRDP: RX ICMP packet too long from %s\n",
+                        inet_ntoa(src));
+               return;
+       }
+
+       icmp = (struct icmphdr *)(p + ip_hlen);
+
+       /* check icmp checksum */
+       if (in_cksum(icmp, datalen) != icmp->checksum) {
+               flog_warn(
+                       EC_ZEBRA_IRDP_BAD_CHECKSUM,
+                       "IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
+                       inet_ntoa(src));
+               return;
+       }
+
+       /* Handle just only IRDP */
+       if (!(icmp->type == ICMP_ROUTERADVERT
+             || icmp->type == ICMP_ROUTERSOLICIT))
+               return;
+
+       if (icmp->code != 0) {
+               flog_warn(EC_ZEBRA_IRDP_BAD_TYPE_CODE,
+                         "IRDP: RX packet type %d from %s. Bad ICMP type code,"
+                         " silently ignored",
+                         icmp->type, inet_ntoa(src));
+               return;
+       }
+
+       if (!((ntohl(ip->ip_dst.s_addr) == INADDR_BROADCAST)
+             && (irdp->flags & IF_BROADCAST))
+           || (ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
+               && !(irdp->flags & IF_BROADCAST))) {
+               flog_warn(
+                       EC_ZEBRA_IRDP_BAD_RX_FLAGS,
+                       "IRDP: RX illegal from %s to %s while %s operates in %s; Please correct settings\n",
+                       inet_ntoa(src),
+                       ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
+                               ? "multicast"
+                               : inet_ntoa(ip->ip_dst),
+                       ifp->name,
+                       irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
+               return;
+       }
+
+       switch (icmp->type) {
+       case ICMP_ROUTERADVERT:
+               break;
+
+       case ICMP_ROUTERSOLICIT:
+
+               if (irdp->flags & IF_DEBUG_MESSAGES)
+                       zlog_debug("IRDP: RX Solicit on %s from %s\n",
+                                  ifp->name, inet_ntoa(src));
+
+               process_solicit(ifp);
+               break;
+
+       default:
+               flog_warn(
+                       EC_ZEBRA_IRDP_BAD_TYPE,
+                       "IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
+                       icmp->type, inet_ntoa(src));
+       }
 }
 
-static int
-irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex)
+static int irdp_recvmsg(int sock, uint8_t *buf, int size, int *ifindex)
 {
-  struct msghdr msg;
-  struct iovec iov;
-  char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )];
-  int ret;
-
-  msg.msg_name = (void *)0;
-  msg.msg_namelen = 0;
-  msg.msg_iov = &iov;
-  msg.msg_iovlen = 1;
-  msg.msg_control = (void *) adata;
-  msg.msg_controllen = sizeof adata;
-
-  iov.iov_base = buf;
-  iov.iov_len = size;
-
-  ret = recvmsg (sock, &msg, 0);
-  if (ret < 0) {
-    zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno));
-    return ret;
-  }
-
-  if (msg.msg_flags & MSG_TRUNC) {
-    zlog_warn("IRDP: recvmsg: truncated message");
-    return ret;
-  }
-  if (msg.msg_flags & MSG_CTRUNC) {
-    zlog_warn("IRDP: recvmsg: truncated control message");
-    return ret;
-  }
-
-  *ifindex = getsockopt_ifindex (AF_INET, &msg);
-
-  return ret;
+       struct msghdr msg;
+       struct iovec iov;
+       char adata[CMSG_SPACE(SOPT_SIZE_CMSG_PKTINFO_IPV4())];
+       int ret;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_name = (void *)0;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = (void *)adata;
+       msg.msg_controllen = sizeof adata;
+
+       iov.iov_base = buf;
+       iov.iov_len = size;
+
+       ret = recvmsg(sock, &msg, 0);
+       if (ret < 0) {
+               flog_warn(EC_LIB_SOCKET, "IRDP: recvmsg: read error %s",
+                         safe_strerror(errno));
+               return ret;
+       }
+
+       if (msg.msg_flags & MSG_TRUNC) {
+               flog_warn(EC_LIB_SOCKET, "IRDP: recvmsg: truncated message");
+               return ret;
+       }
+       if (msg.msg_flags & MSG_CTRUNC) {
+               flog_warn(EC_LIB_SOCKET,
+                         "IRDP: recvmsg: truncated control message");
+               return ret;
+       }
+
+       *ifindex = getsockopt_ifindex(AF_INET, &msg);
+
+       return ret;
 }
 
 int irdp_read_raw(struct thread *r)
 {
-  struct interface *ifp;
-  struct zebra_if *zi;
-  struct irdp_interface *irdp;
-  char buf[IRDP_RX_BUF];
-  int ret, ifindex = 0;
-  
-  int irdp_sock = THREAD_FD (r);
-  t_irdp_raw = NULL;
-  thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock, &t_irdp_raw);
-  
-  ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF,  &ifindex);
-  if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
-
-  ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
-  if(! ifp ) return ret;
-
-  zi= ifp->info;
-  if(! zi ) return ret;
-
-  irdp = &zi->irdp;
-  if(! irdp ) return ret;
-
-  if(! (irdp->flags & IF_ACTIVE)) {
-
-    if(irdp->flags & IF_DEBUG_MISC) 
-      zlog_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name);
-    return 0;
-  }
-
-  if(irdp->flags & IF_DEBUG_PACKET) {
-    int i;
-    zlog_debug("IRDP: RX (idx %d) ", ifindex);
-    for(i=0; i < ret; i++) zlog_debug( "IRDP: RX %x ", buf[i]&0xFF);
-  }
-
-  parse_irdp_packet(buf, ret, ifp);
-
-  return ret;
-}
+       struct interface *ifp;
+       struct zebra_if *zi;
+       struct irdp_interface *irdp;
+       char buf[IRDP_RX_BUF];
+       int ret, ifindex = 0;
 
-void 
-send_packet(struct interface *ifp, 
-           struct stream *s,
-           u_int32_t dst,
-           struct prefix *p,
-           u_int32_t ttl)
-{
-  static struct sockaddr_in sockdst = {AF_INET};
-  struct ip *ip;
-  struct icmphdr *icmp;
-  struct msghdr *msg;
-  struct cmsghdr *cmsg;
-  struct iovec iovector;
-  char msgbuf[256];
-  char buf[256];
-  struct in_pktinfo *pktinfo;
-  u_long src;
-  u_char on;
-  if (!(ifp->flags & IFF_UP))
-    return;
-
-  if (p)
-    src = ntohl(p->u.prefix4.s_addr);
-  else 
-    src = 0; /* Is filled in */
-  
-  ip = (struct ip *) buf;
-  ip->ip_hl = sizeof(struct ip) >> 2;
-  ip->ip_v = IPVERSION;
-  ip->ip_tos = 0xC0;
-  ip->ip_off = 0L;
-  ip->ip_p = 1;       /* IP_ICMP */
-  ip->ip_ttl = ttl;
-  ip->ip_src.s_addr = src;
-  ip->ip_dst.s_addr = dst;
-  icmp = (struct icmphdr *) (buf + sizeof (struct ip));
-
-  /* Merge IP header with icmp packet */
-  assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip)));
-  stream_get(icmp, s, stream_get_endp(s));
-
-  /* icmp->checksum is already calculated */
-  ip->ip_len  = sizeof(struct ip) + stream_get_endp(s);
-
-  on = 1;
-  if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
-                (char *) &on, sizeof(on)) < 0)
-    zlog_warn("sendto %s", safe_strerror (errno));
-
-
-  if(dst == INADDR_BROADCAST ) {
-    on = 1;
-    if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
-                  (char *) &on, sizeof(on)) < 0)
-      zlog_warn("sendto %s", safe_strerror (errno));
-  }
-
-  if(dst !=  INADDR_BROADCAST)
-    setsockopt_ipv4_multicast_loop (irdp_sock, 0);
-
-  memset(&sockdst,0,sizeof(sockdst));
-  sockdst.sin_family=AF_INET;
-  sockdst.sin_addr.s_addr = dst;
-
-  cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
-  cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
-  cmsg->cmsg_level = SOL_IP;
-  cmsg->cmsg_type = IP_PKTINFO;
-  pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
-  pktinfo->ipi_ifindex = ifp->ifindex;
-  pktinfo->ipi_spec_dst.s_addr = src;
-  pktinfo->ipi_addr.s_addr = src;
-  iovector.iov_base = (void *) buf;
-  iovector.iov_len = ip->ip_len; 
-  msg = (struct msghdr *) msgbuf;
-  msg->msg_name = &sockdst;
-  msg->msg_namelen = sizeof(sockdst);
-  msg->msg_iov = &iovector;
-  msg->msg_iovlen = 1;
-  msg->msg_control = cmsg;
-  msg->msg_controllen = cmsg->cmsg_len;
-  sockopt_iphdrincl_swab_htosys (ip);
-  
-  if (sendmsg(irdp_sock, msg, 0) < 0) {
-    zlog_warn("sendto %s", safe_strerror (errno));
-  }
-  /*   printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
-}
+       int irdp_sock = THREAD_FD(r);
+       t_irdp_raw = NULL;
+       thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock,
+                       &t_irdp_raw);
+
+       ret = irdp_recvmsg(irdp_sock, (uint8_t *)buf, IRDP_RX_BUF, &ifindex);
+
+       if (ret < 0)
+               flog_warn(EC_LIB_SOCKET, "IRDP: RX Error length = %d", ret);
+
+       ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+       if (!ifp)
+               return ret;
+
+       zi = ifp->info;
+       if (!zi)
+               return ret;
 
+       irdp = zi->irdp;
+       if (!irdp)
+               return ret;
 
-#endif /* HAVE_IRDP */
+       if (!(irdp->flags & IF_ACTIVE)) {
 
+               if (irdp->flags & IF_DEBUG_MISC)
+                       zlog_debug("IRDP: RX ICMP for disabled interface %s\n",
+                                  ifp->name);
+               return 0;
+       }
 
+       if (irdp->flags & IF_DEBUG_PACKET) {
+               int i;
+               zlog_debug("IRDP: RX (idx %d) ", ifindex);
+               for (i = 0; i < ret; i++)
+                       zlog_debug("IRDP: RX %x ", buf[i] & 0xFF);
+       }
 
+       parse_irdp_packet(buf, ret, ifp);
+
+       return ret;
+}
+
+void send_packet(struct interface *ifp, struct stream *s, uint32_t dst,
+                struct prefix *p, uint32_t ttl)
+{
+       static struct sockaddr_in sockdst = {AF_INET};
+       struct ip *ip;
+       struct icmphdr *icmp;
+       struct msghdr *msg;
+       struct cmsghdr *cmsg;
+       struct iovec iovector;
+       char msgbuf[256];
+       char buf[256];
+       struct in_pktinfo *pktinfo;
+       unsigned long src;
+       uint8_t on;
+
+       if (!(ifp->flags & IFF_UP))
+               return;
+
+       if (p)
+               src = ntohl(p->u.prefix4.s_addr);
+       else
+               src = 0; /* Is filled in */
+
+       ip = (struct ip *)buf;
+       ip->ip_hl = sizeof(struct ip) >> 2;
+       ip->ip_v = IPVERSION;
+       ip->ip_tos = 0xC0;
+       ip->ip_off = 0L;
+       ip->ip_p = 1; /* IP_ICMP */
+       ip->ip_ttl = ttl;
+       ip->ip_src.s_addr = src;
+       ip->ip_dst.s_addr = dst;
+       icmp = (struct icmphdr *)(buf + sizeof(struct ip));
+
+       /* Merge IP header with icmp packet */
+       assert(stream_get_endp(s) < (sizeof(buf) - sizeof(struct ip)));
+       stream_get(icmp, s, stream_get_endp(s));
+
+       /* icmp->checksum is already calculated */
+       ip->ip_len = sizeof(struct ip) + stream_get_endp(s);
+
+       on = 1;
+       if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
+                      sizeof(on))
+           < 0)
+               zlog_debug("sendto %s", safe_strerror(errno));
+
+
+       if (dst == INADDR_BROADCAST) {
+               on = 1;
+               if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
+                              sizeof(on))
+                   < 0)
+                       zlog_debug("sendto %s", safe_strerror(errno));
+       }
+
+       if (dst != INADDR_BROADCAST)
+               setsockopt_ipv4_multicast_loop(irdp_sock, 0);
+
+       memset(&sockdst, 0, sizeof(sockdst));
+       sockdst.sin_family = AF_INET;
+       sockdst.sin_addr.s_addr = dst;
+
+       cmsg = (struct cmsghdr *)(msgbuf + sizeof(struct msghdr));
+       cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
+       cmsg->cmsg_level = SOL_IP;
+       cmsg->cmsg_type = IP_PKTINFO;
+       pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
+       pktinfo->ipi_ifindex = ifp->ifindex;
+       pktinfo->ipi_spec_dst.s_addr = src;
+       pktinfo->ipi_addr.s_addr = src;
+
+       iovector.iov_base = (void *)buf;
+       iovector.iov_len = ip->ip_len;
+       msg = (struct msghdr *)msgbuf;
+       msg->msg_name = &sockdst;
+       msg->msg_namelen = sizeof(sockdst);
+       msg->msg_iov = &iovector;
+       msg->msg_iovlen = 1;
+       msg->msg_control = cmsg;
+       msg->msg_controllen = cmsg->cmsg_len;
+
+       sockopt_iphdrincl_swab_htosys(ip);
+
+       if (sendmsg(irdp_sock, msg, 0) < 0) {
+               zlog_debug("sendto %s", safe_strerror(errno));
+       }
+       /*   printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
+}