File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / igmpproxy / src / igmp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:00:29 2012 UTC (12 years, 4 months ago) by misho
Branches: igmpproxy, MAIN
CVS tags: v0_1p0, v0_1, HEAD
igmpproxy

    1: /*
    2: **  igmpproxy - IGMP proxy based multicast router 
    3: **  Copyright (C) 2005 Johnny Egeland <johnny@rlo.org>
    4: **
    5: **  This program is free software; you can redistribute it and/or modify
    6: **  it under the terms of the GNU General Public License as published by
    7: **  the Free Software Foundation; either version 2 of the License, or
    8: **  (at your option) any later version.
    9: **
   10: **  This program is distributed in the hope that it will be useful,
   11: **  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12: **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13: **  GNU General Public License for more details.
   14: **
   15: **  You should have received a copy of the GNU General Public License
   16: **  along with this program; if not, write to the Free Software
   17: **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   18: **
   19: **----------------------------------------------------------------------------
   20: **
   21: **  This software is derived work from the following software. The original
   22: **  source code has been modified from it's original state by the author
   23: **  of igmpproxy.
   24: **
   25: **  smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de>
   26: **  - Licensed under the GNU General Public License, version 2
   27: **  
   28: **  mrouted 3.9-beta3 - COPYRIGHT 1989 by The Board of Trustees of 
   29: **  Leland Stanford Junior University.
   30: **  - Original license can be found in the Stanford.txt file.
   31: **
   32: */
   33: /**
   34: *   igmp.h - Recieves IGMP requests, and handle them 
   35: *            appropriately...
   36: */
   37: 
   38: #include "igmpproxy.h"
   39:  
   40: // Globals                  
   41: uint32_t     allhosts_group;          /* All hosts addr in net order */
   42: uint32_t     allrouters_group;          /* All hosts addr in net order */
   43:               
   44: extern int MRouterFD;
   45: 
   46: /*
   47:  * Open and initialize the igmp socket, and fill in the non-changing
   48:  * IP header fields in the output packet buffer.
   49:  */
   50: void initIgmp() {
   51:     struct ip *ip;
   52: 
   53:     recv_buf = malloc(RECV_BUF_SIZE);
   54:     send_buf = malloc(RECV_BUF_SIZE);
   55: 
   56:     k_hdr_include(true);    /* include IP header when sending */
   57:     k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering        */
   58:     k_set_ttl(1);       /* restrict multicasts to one hop */
   59:     k_set_loop(false);      /* disable multicast loopback     */
   60: 
   61:     ip         = (struct ip *)send_buf;
   62:     memset(ip, 0, sizeof(struct ip));
   63:     /*
   64:      * Fields zeroed that aren't filled in later:
   65:      * - IP ID (let the kernel fill it in)
   66:      * - Offset (we don't send fragments)
   67:      * - Checksum (let the kernel fill it in)
   68:      */
   69:     ip->ip_v   = IPVERSION;
   70:     ip->ip_hl  = sizeof(struct ip) >> 2;
   71:     ip->ip_tos = 0xc0;      /* Internet Control */
   72:     ip->ip_ttl = MAXTTL;    /* applies to unicasts only */
   73:     ip->ip_p   = IPPROTO_IGMP;
   74: 
   75:     allhosts_group   = htonl(INADDR_ALLHOSTS_GROUP);
   76:     allrouters_group = htonl(INADDR_ALLRTRS_GROUP);
   77: }
   78: 
   79: /**
   80: *   Finds the textual name of the supplied IGMP request.
   81: */
   82: char *igmpPacketKind(u_int type, u_int code) {
   83:     static char unknown[20];
   84: 
   85:     switch (type) {
   86:     case IGMP_MEMBERSHIP_QUERY:     return  "Membership query  ";
   87:     case IGMP_V1_MEMBERSHIP_REPORT:  return "V1 member report  ";
   88:     case IGMP_V2_MEMBERSHIP_REPORT:  return "V2 member report  ";
   89:     case IGMP_V2_LEAVE_GROUP:        return "Leave message     ";
   90:     
   91:     default:
   92:         sprintf(unknown, "unk: 0x%02x/0x%02x    ", type, code);
   93:         return unknown;
   94:     }
   95: }
   96: 
   97: 
   98: /**
   99:  * Process a newly received IGMP packet that is sitting in the input
  100:  * packet buffer.
  101:  */
  102: void acceptIgmp(int recvlen) {
  103:     register uint32_t src, dst, group;
  104:     struct ip *ip;
  105:     struct igmp *igmp;
  106:     int ipdatalen, iphdrlen, igmpdatalen;
  107: 
  108:     if (recvlen < sizeof(struct ip)) {
  109:         my_log(LOG_WARNING, 0,
  110:             "received packet too short (%u bytes) for IP header", recvlen);
  111:         return;
  112:     }
  113: 
  114:     ip        = (struct ip *)recv_buf;
  115:     src       = ip->ip_src.s_addr;
  116:     dst       = ip->ip_dst.s_addr;
  117: 
  118:     /* 
  119:      * this is most likely a message from the kernel indicating that
  120:      * a new src grp pair message has arrived and so, it would be 
  121:      * necessary to install a route into the kernel for this.
  122:      */
  123:     if (ip->ip_p == 0) {
  124:         if (src == 0 || dst == 0) {
  125:             my_log(LOG_WARNING, 0, "kernel request not accurate");
  126:         }
  127:         else {
  128:             struct IfDesc *checkVIF;
  129:             
  130:             // Check if the source address matches a valid address on upstream vif.
  131:             checkVIF = getIfByIx( upStreamVif );
  132:             if(checkVIF == 0) {
  133:                 my_log(LOG_ERR, 0, "Upstream VIF was null.");
  134:                 return;
  135:             } 
  136:             else if(src == checkVIF->InAdr.s_addr) {
  137:                 my_log(LOG_NOTICE, 0, "Route activation request from %s for %s is from myself. Ignoring.",
  138:                     inetFmt(src, s1), inetFmt(dst, s2));
  139:                 return;
  140:             }
  141:             else if(!isAdressValidForIf(checkVIF, src)) {
  142:                 my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
  143:                     inetFmt(src, s1), inetFmt(dst, s2));
  144:                 return;
  145:             }
  146:             
  147:             // Activate the route.
  148:             my_log(LOG_DEBUG, 0, "Route activate request from %s to %s",
  149: 		    inetFmt(src,s1), inetFmt(dst,s2));
  150:             activateRoute(dst, src);
  151:             
  152: 
  153:         }
  154:         return;
  155:     }
  156: 
  157:     iphdrlen  = ip->ip_hl << 2;
  158:     ipdatalen = ip_data_len(ip);
  159: 
  160:     if (iphdrlen + ipdatalen != recvlen) {
  161:         my_log(LOG_WARNING, 0,
  162:             "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
  163:             inetFmt(src, s1), recvlen, iphdrlen, ipdatalen);
  164:         return;
  165:     }
  166: 
  167:     igmp        = (struct igmp *)(recv_buf + iphdrlen);
  168:     group       = igmp->igmp_group.s_addr;
  169:     igmpdatalen = ipdatalen - IGMP_MINLEN;
  170:     if (igmpdatalen < 0) {
  171:         my_log(LOG_WARNING, 0,
  172:             "received IP data field too short (%u bytes) for IGMP, from %s",
  173:             ipdatalen, inetFmt(src, s1));
  174:         return;
  175:     }
  176: 
  177:     my_log(LOG_NOTICE, 0, "RECV %s from %-15s to %s",
  178:         igmpPacketKind(igmp->igmp_type, igmp->igmp_code),
  179:         inetFmt(src, s1), inetFmt(dst, s2) );
  180: 
  181:     switch (igmp->igmp_type) {
  182:     case IGMP_V1_MEMBERSHIP_REPORT:
  183:     case IGMP_V2_MEMBERSHIP_REPORT:
  184:         acceptGroupReport(src, group, igmp->igmp_type);
  185:         return;
  186:     
  187:     case IGMP_V2_LEAVE_GROUP:
  188:         acceptLeaveMessage(src, group);
  189:         return;
  190:     
  191:     case IGMP_MEMBERSHIP_QUERY:
  192:         return;
  193: 
  194:     default:
  195:         my_log(LOG_INFO, 0,
  196:             "ignoring unknown IGMP message type %x from %s to %s",
  197:             igmp->igmp_type, inetFmt(src, s1),
  198:             inetFmt(dst, s2));
  199:         return;
  200:     }
  201: }
  202: 
  203: 
  204: /*
  205:  * Construct an IGMP message in the output packet buffer.  The caller may
  206:  * have already placed data in that buffer, of length 'datalen'.
  207:  */
  208: void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
  209:     struct ip *ip;
  210:     struct igmp *igmp;
  211:     extern int curttl;
  212: 
  213:     ip                      = (struct ip *)send_buf;
  214:     ip->ip_src.s_addr       = src;
  215:     ip->ip_dst.s_addr       = dst;
  216:     ip_set_len(ip, MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen);
  217: 
  218:     if (IN_MULTICAST(ntohl(dst))) {
  219:         ip->ip_ttl = curttl;
  220:     } else {
  221:         ip->ip_ttl = MAXTTL;
  222:     }
  223: 
  224:     igmp                    = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
  225:     igmp->igmp_type         = type;
  226:     igmp->igmp_code         = code;
  227:     igmp->igmp_group.s_addr = group;
  228:     igmp->igmp_cksum        = 0;
  229:     igmp->igmp_cksum        = inetChksum((u_short *)igmp,
  230:                                          IGMP_MINLEN + datalen);
  231: }
  232: 
  233: /* 
  234:  * Call build_igmp() to build an IGMP message in the output packet buffer.
  235:  * Then send the message from the interface with IP address 'src' to
  236:  * destination 'dst'.
  237:  */
  238: void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
  239:     struct sockaddr_in sdst;
  240:     int setloop = 0, setigmpsource = 0;
  241: 
  242:     buildIgmp(src, dst, type, code, group, datalen);
  243: 
  244:     if (IN_MULTICAST(ntohl(dst))) {
  245:         k_set_if(src);
  246:         setigmpsource = 1;
  247:         if (type != IGMP_DVMRP || dst == allhosts_group) {
  248:             setloop = 1;
  249:             k_set_loop(true);
  250:         }
  251:     }
  252: 
  253:     memset(&sdst, 0, sizeof(sdst));
  254:     sdst.sin_family = AF_INET;
  255: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  256:     sdst.sin_len = sizeof(sdst);
  257: #endif
  258:     sdst.sin_addr.s_addr = dst;
  259:     if (sendto(MRouterFD, send_buf,
  260:                MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0,
  261:                (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
  262:         if (errno == ENETDOWN)
  263:             my_log(LOG_ERR, errno, "Sender VIF was down.");
  264:         else
  265:             my_log(LOG_INFO, errno,
  266:                 "sendto to %s on %s",
  267:                 inetFmt(dst, s1), inetFmt(src, s2));
  268:     }
  269: 
  270:     if(setigmpsource) {
  271:         if (setloop) {
  272:             k_set_loop(false);
  273:         }
  274:         // Restore original...
  275:         k_set_if(INADDR_ANY);
  276:     }
  277: 
  278:     my_log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
  279: 	    igmpPacketKind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
  280: 	    inetFmt(src, s1), inetFmt(dst, s2));
  281: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>