Annotation of embedaddon/quagga/zebra/irdp_packet.c, revision 1.1
1.1 ! misho 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>