mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 04:50:35 +00:00 
			
		
		
		
	We were including 'extern struct zebra_t zebrad;' all over the place. This made no sense. Refactor into zserv.h where the definition was and remove resulting unnecessary code. Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com> Reviewed-by: Don Slice <dslice@cumulusnetworks.com> Reviewed-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
		
			
				
	
	
		
			368 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			368 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *
 | 
						|
 * Copyright (C) 2000  Robert Olsson.
 | 
						|
 * Swedish University of Agricultural Sciences
 | 
						|
 *
 | 
						|
 * This file is part of GNU Zebra.
 | 
						|
 *
 | 
						|
 * GNU Zebra is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms of the GNU General Public License as published by the
 | 
						|
 * Free Software Foundation; either version 2, or (at your option) any
 | 
						|
 * later version.
 | 
						|
 *
 | 
						|
 * GNU Zebra is distributed in the hope that it will be useful, but
 | 
						|
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
 | 
						|
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
						|
 * 02111-1307, 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
 | 
						|
 * for reviewing and tests.
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
 | 
						|
#ifdef HAVE_IRDP
 | 
						|
 | 
						|
#include "if.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "sockunion.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "command.h"
 | 
						|
#include "memory.h"
 | 
						|
#include "stream.h"
 | 
						|
#include "ioctl.h"
 | 
						|
#include "connected.h"
 | 
						|
#include "log.h"
 | 
						|
#include "zclient.h"
 | 
						|
#include "thread.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"
 | 
						|
 | 
						|
 | 
						|
/* GLOBAL VARS */
 | 
						|
 | 
						|
int irdp_sock = -1;
 | 
						|
 | 
						|
extern struct thread *t_irdp_raw;
 | 
						|
 | 
						|
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));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
irdp_recvmsg (int sock, u_char *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;
 | 
						|
}
 | 
						|
 | 
						|
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 = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
 | 
						|
  
 | 
						|
  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);
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
  int 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) {
 | 
						|
      on = 0; 
 | 
						|
      if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP, 
 | 
						|
		     (char *)&on,sizeof(on)) < 0)
 | 
						|
	zlog_warn("sendto %s", safe_strerror (errno));
 | 
						|
  }
 | 
						|
 | 
						|
  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); */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#endif /* HAVE_IRDP */
 | 
						|
 | 
						|
 | 
						|
 |