File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mrouted / kern.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:10:48 2012 UTC (12 years, 3 months ago) by misho
Branches: mrouted, MAIN
CVS tags: v3_9_6p0, v3_9_6, v3_9_5, HEAD
mrouted

    1: /*
    2:  * The mrouted program is covered by the license in the accompanying file
    3:  * named "LICENSE".  Use of the mrouted program represents acceptance of
    4:  * the terms and conditions listed in that file.
    5:  *
    6:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
    7:  * Leland Stanford Junior University.
    8:  */
    9: 
   10: #include "defs.h"
   11: 
   12: int curttl = 0;
   13: 
   14: /*
   15:  * Open/init the multicast routing in the kernel and sets the
   16:  * MRT_PIM (aka MRT_ASSERT) flag in the kernel.
   17:  */
   18: void k_init_dvmrp(void)
   19: {
   20: #ifdef OLD_KERNEL
   21:     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT, (char *)NULL, 0) < 0) {
   22: #else
   23:     int v = 1;
   24: 
   25:     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT, (char *)&v, sizeof(int)) < 0) {
   26: #endif
   27: 	if (errno == EADDRINUSE)
   28: 	    logit(LOG_ERR, 0, "Another multicast routing application is already running.");
   29: 	else
   30: 	    logit(LOG_ERR, errno, "Cannot enable multicast routing in kernel");
   31:     }
   32: }
   33: 
   34: 
   35: /*
   36:  * Stops the multicast routing in the kernel and resets the
   37:  * MRT_PIM (aka MRT_ASSERT) flag in the kernel.
   38:  */
   39: void k_stop_dvmrp(void)
   40: {
   41:     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE, (char *)NULL, 0) < 0)
   42: 	logit(LOG_WARNING, errno, "Cannot disable multicast routing in kernel");
   43: }
   44: 
   45: 
   46: /*
   47:  * Set the socket receiving buffer. `bufsize` is the preferred size,
   48:  * `minsize` is the smallest acceptable size.
   49:  */
   50: void k_set_rcvbuf(int bufsize, int minsize)
   51: {
   52:     int delta = bufsize / 2;
   53:     int iter = 0;
   54: 
   55:     /*
   56:      * Set the socket buffer.  If we can't set it as large as we want, search around
   57:      * to try to find the highest acceptable value.  The highest acceptable value
   58:      * being smaller than minsize is a fatal error.
   59:      */
   60:     if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) {
   61:         bufsize -= delta;
   62:         while (1) {
   63:             iter++;
   64:             if (delta > 1)
   65:                 delta /= 2;
   66: 
   67:             if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) {
   68:                 bufsize -= delta;
   69:             } else {
   70:                 if (delta < 1024)
   71:                     break;
   72:                 bufsize += delta;
   73:             }
   74:         }
   75:         if (bufsize < minsize) {
   76:             logit(LOG_ERR, 0, "OS-allowed recv buffer size %u < app min %u", bufsize, minsize);
   77:             /*NOTREACHED*/
   78:         }
   79:     }
   80:     IF_DEBUG(DEBUG_KERN) {
   81:         logit(LOG_DEBUG, 0, "Got %d byte recv buffer size in %d iterations",
   82:               bufsize, iter);
   83:     }
   84: }
   85: 
   86: 
   87: /*
   88:  * Set/reset the IP_HDRINCL option. My guess is we don't need it for raw
   89:  * sockets, but having it here won't hurt. Well, unless you are running
   90:  * an older version of FreeBSD (older than 2.2.2). If the multicast
   91:  * raw packet is bigger than 208 bytes, then IP_HDRINCL triggers a bug
   92:  * in the kernel and "panic". The kernel patch for netinet/ip_raw.c
   93:  * coming with this distribution fixes it.
   94:  */
   95: void k_hdr_include(int bool)
   96: {
   97: #ifdef IP_HDRINCL
   98:     if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL, (char *)&bool, sizeof(bool)) < 0)
   99:         logit(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
  100: #endif
  101: }
  102: 
  103: 
  104: /*
  105:  * Set the default TTL for the multicast packets outgoing from this socket.
  106:  */
  107: void k_set_ttl(int t)
  108: {
  109:     u_char ttl;
  110: 
  111:     ttl = t;
  112:     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) < 0)
  113: 	logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
  114: 
  115:     curttl = t;
  116: }
  117: 
  118: 
  119: /*
  120:  * Set/reset the IP_MULTICAST_LOOP. Set/reset is specified by "flag".
  121:  */
  122: void k_set_loop(int flag)
  123: {
  124:     u_char loop;
  125: 
  126:     loop = flag;
  127:     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loop, sizeof(loop)) < 0)
  128:         logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
  129: }
  130: 
  131: 
  132: /*
  133:  * Set the IP_MULTICAST_IF option on local interface ifa.
  134:  */
  135: void k_set_if(u_int32 ifa)
  136: {
  137:     struct in_addr adr;
  138: 
  139:     adr.s_addr = ifa;
  140:     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&adr, sizeof(adr)) < 0) {
  141:         if (errno == EADDRNOTAVAIL || errno == EINVAL)
  142:             return;
  143:         logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
  144:               inet_fmt(ifa, s1, sizeof(s1)));
  145:     }
  146: }
  147: 
  148: 
  149: /*
  150:  * Join a multicast group.
  151:  */
  152: void k_join(u_int32 grp, u_int32 ifa)
  153: {
  154:     struct ip_mreq mreq;
  155: 
  156:     mreq.imr_multiaddr.s_addr = grp;
  157:     mreq.imr_interface.s_addr = ifa;
  158: 
  159:     if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
  160: 	logit(LOG_WARNING, errno, "Cannot join group %s on interface %s",
  161: 	      inet_fmt(grp, s1, sizeof(s1)), inet_fmt(ifa, s2, sizeof(s2)));
  162: }
  163: 
  164: 
  165: /*
  166:  * Leave a multicast group.
  167:  */
  168: void k_leave(u_int32 grp, u_int32 ifa)
  169: {
  170:     struct ip_mreq mreq;
  171: 
  172:     mreq.imr_multiaddr.s_addr = grp;
  173:     mreq.imr_interface.s_addr = ifa;
  174: 
  175:     if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
  176: 	logit(LOG_WARNING, errno, "Cannot leave group %s on interface %s",
  177: 	      inet_fmt(grp, s1, sizeof(s1)), inet_fmt(ifa, s2, sizeof(s2)));
  178: }
  179: 
  180: /*
  181:  * Fill struct vifctl using corresponding fields from struct uvif.
  182:  */
  183: static void uvif_to_vifctl(struct vifctl *vc, struct uvif *v)
  184: {
  185:     vc->vifc_flags           = v->uv_flags & VIFF_KERNEL_FLAGS;
  186:     vc->vifc_threshold       = v->uv_threshold;
  187:     vc->vifc_rate_limit	     = v->uv_rate_limit;
  188:     vc->vifc_lcl_addr.s_addr = v->uv_lcl_addr;
  189:     vc->vifc_rmt_addr.s_addr = v->uv_rmt_addr;
  190: }
  191: 
  192: /*
  193:  * Add a virtual interface in the kernel.
  194:  */
  195: void k_add_vif(vifi_t vifi, struct uvif *v)
  196: {
  197:     struct vifctl vc;
  198: 
  199:     vc.vifc_vifi = vifi;
  200:     uvif_to_vifctl(&vc, v);
  201:     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF, (char *)&vc, sizeof(vc)) < 0)
  202: 	logit(LOG_ERR, errno, "setsockopt MRT_ADD_VIF on vif %d", vifi);
  203: }
  204: 
  205: 
  206: /*
  207:  * Delete a virtual interface in the kernel.
  208:  */
  209: void k_del_vif(vifi_t vifi, struct uvif UNUSED *v)
  210: {
  211:     /*
  212:      * Unfortunately Linux setsocopt MRT_DEL_VIF API differs a bit from the *BSD one.
  213:      * It expects to receive a pointer to struct vifctl that corresponds to the VIF
  214:      * we're going to delete.  *BSD systems on the other hand exepect only the index
  215:      * of that VIF.
  216:      */
  217: #ifdef __linux__
  218:     struct vifctl vc;
  219: 
  220:     vc.vifc_vifi = vifi;
  221:     uvif_to_vifctl(&vc, v);
  222: 
  223:     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF, (char *)&vc, sizeof(vc)) < 0)
  224: #else /* *BSD et al. */
  225:     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF, (char *)&vifi, sizeof(vifi)) < 0)
  226: #endif /* !__linux__ */
  227:     {
  228:         if (errno == EADDRNOTAVAIL || errno == EINVAL)
  229:             return;
  230: 
  231: 	logit(LOG_ERR, errno, "setsockopt MRT_DEL_VIF on vif %d", vifi);
  232:     }
  233: }
  234: 
  235: 
  236: /*
  237:  * Adds a (source, mcastgrp) entry to the kernel
  238:  */
  239: void k_add_rg(u_int32 origin, struct gtable *g)
  240: {
  241:     struct mfcctl mc;
  242:     vifi_t i;
  243: 
  244: #ifdef DEBUG_MFC
  245:     md_log(MD_ADD, origin, g->gt_mcastgrp);
  246: #endif
  247:     /* copy table values so that setsockopt can process it */
  248:     mc.mfcc_origin.s_addr = origin;
  249: #ifdef OLD_KERNEL
  250:     mc.mfcc_originmask.s_addr = 0xffffffff;
  251: #endif
  252:     mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
  253:     mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF;
  254:     for (i = 0; i < numvifs; i++)
  255: 	mc.mfcc_ttls[i] = g->gt_ttls[i];
  256: 
  257:     /* write to kernel space */
  258:     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
  259: 		   (char *)&mc, sizeof(mc)) < 0) {
  260: #ifdef DEBUG_MFC
  261: 	md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
  262: #endif
  263: 	logit(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC",
  264: 		inet_fmt(origin, s1, sizeof(s1)), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
  265:     }
  266: }
  267: 
  268: 
  269: /*
  270:  * Deletes a (source, mcastgrp) entry from the kernel
  271:  */
  272: int k_del_rg(u_int32 origin, struct gtable *g)
  273: {
  274:     struct mfcctl mc;
  275: 
  276: #ifdef DEBUG_MFC
  277:     md_log(MD_DEL, origin, g->gt_mcastgrp);
  278: #endif
  279:     /* copy table values so that setsockopt can process it */
  280:     mc.mfcc_origin.s_addr = origin;
  281: #ifdef OLD_KERNEL
  282:     mc.mfcc_originmask.s_addr = 0xffffffff;
  283: #endif
  284:     mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
  285: 
  286:     /* write to kernel space */
  287:     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC, (char *)&mc, sizeof(mc)) < 0) {
  288: #ifdef DEBUG_MFC
  289: 	md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
  290: #endif
  291: 	logit(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC of (%s %s)",
  292: 	      inet_fmt(origin, s1, sizeof(s1)), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
  293: 
  294: 	return -1;
  295:     }
  296: 
  297:     return 0;
  298: }	
  299: 
  300: /*
  301:  * Get the kernel's idea of what version of mrouted needs to run with it.
  302:  */
  303: int k_get_version(void)
  304: {
  305: #ifdef OLD_KERNEL
  306:     return -1;
  307: #else
  308:     int vers;
  309:     socklen_t len = sizeof(vers);
  310: 
  311:     if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION, (char *)&vers, &len) < 0)
  312: 	logit(LOG_ERR, errno, "getsockopt MRT_VERSION: perhaps your kernel is too old?");
  313: 
  314:     return vers;
  315: #endif
  316: }
  317: 
  318: #if 0
  319: /*
  320:  * Get packet counters
  321:  */
  322: int k_get_vif_count(vifi_t vifi, int *icount, int *ocount, int *ibytes, int *obytes)
  323: {
  324:     struct sioc_vif_req vreq;
  325:     int retval = 0;
  326: 
  327:     vreq.vifi = vifi;
  328:     if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&vreq) < 0) {
  329: 	logit(LOG_WARNING, errno, "SIOCGETVIFCNT on vif %d", vifi);
  330: 	vreq.icount = vreq.ocount = vreq.ibytes =
  331: 		vreq.obytes = 0xffffffff;
  332: 	retval = 1;
  333:     }
  334:     if (icount)
  335: 	*icount = vreq.icount;
  336:     if (ocount)
  337: 	*ocount = vreq.ocount;
  338:     if (ibytes)
  339: 	*ibytes = vreq.ibytes;
  340:     if (obytes)
  341: 	*obytes = vreq.obytes;
  342:     return retval;
  343: }
  344: 
  345: /*
  346:  * Get counters for a desired source and group.
  347:  */
  348: int k_get_sg_count(u_int32 src, u_int32 grp, int *pktcnt, int *bytecnt, int *wrong_if)
  349: {
  350:     struct sioc_sg_req sgreq;
  351:     int retval = 0;
  352: 
  353:     sgreq.src.s_addr = src;
  354:     sgreq.grp.s_addr = grp;
  355:     if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sgreq) < 0) {
  356: 	logit(LOG_WARNING, errno, "SIOCGETSGCNT on (%s %s)",
  357: 	    inet_fmt(src, s1, sizeof(s1)), inet_fmt(grp, s2, sizeof(s2)));
  358: 	sgreq.pktcnt = sgreq.bytecnt = sgreq.wrong_if = 0xffffffff;
  359: 	return 1;
  360:     }
  361:     if (pktcnt)
  362:     	*pktcnt = sgreq.pktcnt;
  363:     if (bytecnt)
  364:     	*bytecnt = sgreq.bytecnt;
  365:     if (wrong_if)
  366:     	*wrong_if = sgreq.wrong_if;
  367: 
  368:     return retval;
  369: }
  370: #endif
  371: 
  372: /**
  373:  * Local Variables:
  374:  *  version-control: t
  375:  *  indent-tabs-mode: t
  376:  *  c-file-style: "ellemtel"
  377:  *  c-basic-offset: 4
  378:  * End:
  379:  */

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