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>