Annotation of embedaddon/mrouted/kern.c, revision 1.1.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>