* 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 */
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); */
+}