Annotation of embedaddon/mrouted/kern.c, revision 1.1

1.1     ! misho       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>