Annotation of embedaddon/pimdd/kern.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1998 by the University of Southern California.
! 3: * All rights reserved.
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software and
! 6: * its documentation in source and binary forms for lawful
! 7: * purposes and without fee is hereby granted, provided
! 8: * that the above copyright notice appear in all copies and that both
! 9: * the copyright notice and this permission notice appear in supporting
! 10: * documentation, and that any documentation, advertising materials,
! 11: * and other materials related to such distribution and use acknowledge
! 12: * that the software was developed by the University of Southern
! 13: * California and/or Information Sciences Institute.
! 14: * The name of the University of Southern California may not
! 15: * be used to endorse or promote products derived from this software
! 16: * without specific prior written permission.
! 17: *
! 18: * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
! 19: * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
! 20: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
! 21: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
! 22: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
! 23: * NON-INFRINGEMENT.
! 24: *
! 25: * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
! 26: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
! 27: * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
! 28: * THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 29: *
! 30: * Other copyrights might apply to parts of this software and are so
! 31: * noted when applicable.
! 32: */
! 33: /*
! 34: * Questions concerning this software should be directed to
! 35: * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
! 36: *
! 37: * $Id: kern.c,v 1.2 1998/06/01 22:27:14 kurtw Exp $
! 38: */
! 39: /*
! 40: * Part of this program has been derived from mrouted.
! 41: * The mrouted program is covered by the license in the accompanying file
! 42: * named "LICENSE.mrouted".
! 43: *
! 44: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
! 45: * Leland Stanford Junior University.
! 46: *
! 47: */
! 48:
! 49: #include "defs.h"
! 50:
! 51: #ifdef RAW_OUTPUT_IS_RAW
! 52: int curttl = 0;
! 53: #endif
! 54:
! 55:
! 56: /*
! 57: * Open/init the multicast routing in the kernel and sets the MRT_ASSERT
! 58: * flag in the kernel.
! 59: *
! 60: */
! 61: void
! 62: k_init_pim(socket)
! 63: int socket;
! 64: {
! 65: int v = 1;
! 66:
! 67: if (setsockopt(socket, IPPROTO_IP, MRT_INIT, (char *)&v, sizeof(int)) < 0)
! 68: log(LOG_ERR, errno, "cannot enable multicast routing in kernel");
! 69:
! 70: if(setsockopt(socket, IPPROTO_IP, MRT_ASSERT, (char *)&v, sizeof(int)) < 0)
! 71: log(LOG_ERR, errno, "cannot set ASSERT flag in kernel");
! 72: }
! 73:
! 74:
! 75: /*
! 76: * Stops the multicast routing in the kernel and resets the MRT_ASSERT
! 77: * flag in the kernel.
! 78: */
! 79: void
! 80: k_stop_pim(socket)
! 81: int socket;
! 82: {
! 83: int v = 0;
! 84:
! 85: if (setsockopt(socket, IPPROTO_IP, MRT_DONE, (char *)NULL, 0) < 0)
! 86: log(LOG_ERR, errno, "cannot disable multicast routing in kernel");
! 87:
! 88: if(setsockopt(socket, IPPROTO_IP, MRT_ASSERT, (char *)&v, sizeof(int)) < 0)
! 89: log(LOG_ERR, errno, "cannot reset ASSERT flag in kernel");
! 90: }
! 91:
! 92:
! 93: /*
! 94: * Set the socket receiving buffer. `bufsize` is the preferred size,
! 95: * `minsize` is the smallest acceptable size.
! 96: */
! 97: void k_set_rcvbuf(socket, bufsize, minsize)
! 98: int socket;
! 99: int bufsize;
! 100: int minsize;
! 101: {
! 102: int delta = bufsize / 2;
! 103: int iter = 0;
! 104:
! 105: /*
! 106: * Set the socket buffer. If we can't set it as large as we
! 107: * want, search around to try to find the highest acceptable
! 108: * value. The highest acceptable value being smaller than
! 109: * minsize is a fatal error.
! 110: */
! 111: if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
! 112: (char *)&bufsize, sizeof(bufsize)) < 0) {
! 113: bufsize -= delta;
! 114: while (1) {
! 115: iter++;
! 116: if (delta > 1)
! 117: delta /= 2;
! 118:
! 119: if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
! 120: (char *)&bufsize, sizeof(bufsize)) < 0) {
! 121: bufsize -= delta;
! 122: } else {
! 123: if (delta < 1024)
! 124: break;
! 125: bufsize += delta;
! 126: }
! 127: }
! 128: if (bufsize < minsize) {
! 129: log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
! 130: bufsize, minsize);
! 131: /*NOTREACHED*/
! 132: }
! 133: }
! 134: IF_DEBUG(DEBUG_KERN)
! 135: log(LOG_DEBUG, 0, "Got %d byte buffer size in %d iterations",
! 136: bufsize, iter);
! 137: }
! 138:
! 139:
! 140: /*
! 141: * Set/reset the IP_HDRINCL option. My guess is we don't need it for raw
! 142: * sockets, but having it here won't hurt. Well, unless you are running
! 143: * an older version of FreeBSD (older than 2.2.2). If the multicast
! 144: * raw packet is bigger than 208 bytes, then IP_HDRINCL triggers a bug
! 145: * in the kernel and "panic". The kernel patch for netinet/ip_raw.c
! 146: * coming with this distribution fixes it.
! 147: */
! 148: void k_hdr_include(socket, bool)
! 149: int socket;
! 150: int bool;
! 151: {
! 152: #ifdef IP_HDRINCL
! 153: if (setsockopt(socket, IPPROTO_IP, IP_HDRINCL,
! 154: (char *)&bool, sizeof(bool)) < 0)
! 155: log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
! 156: #endif
! 157: }
! 158:
! 159:
! 160: /*
! 161: * Set the default TTL for the multicast packets outgoing from this
! 162: * socket.
! 163: * TODO: Does it affect the unicast packets?
! 164: */
! 165: void k_set_ttl(socket, t)
! 166: int socket;
! 167: int t;
! 168: {
! 169: #ifdef RAW_OUTPUT_IS_RAW
! 170: curttl = t;
! 171: #else
! 172: u_char ttl;
! 173:
! 174: ttl = t;
! 175: if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL,
! 176: (char *)&ttl, sizeof(ttl)) < 0)
! 177: log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
! 178: #endif
! 179: }
! 180:
! 181:
! 182: /*
! 183: * Set/reset the IP_MULTICAST_LOOP. Set/reset is specified by "flag".
! 184: */
! 185: void k_set_loop(socket, flag)
! 186: int socket;
! 187: int flag;
! 188: {
! 189: u_char loop;
! 190:
! 191: loop = flag;
! 192: if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP,
! 193: (char *)&loop, sizeof(loop)) < 0)
! 194: log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
! 195: }
! 196:
! 197:
! 198: /*
! 199: * Set the IP_MULTICAST_IF option on local interface ifa.
! 200: */
! 201: void k_set_if(socket, ifa)
! 202: int socket;
! 203: u_int32 ifa;
! 204: {
! 205: struct in_addr adr;
! 206:
! 207: adr.s_addr = ifa;
! 208: if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF,
! 209: (char *)&adr, sizeof(adr)) < 0)
! 210: log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
! 211: inet_fmt(ifa, s1));
! 212: }
! 213:
! 214:
! 215: /*
! 216: * Join a multicast grp group on local interface ifa.
! 217: */
! 218: void k_join(socket, grp, ifa)
! 219: int socket;
! 220: u_int32 grp;
! 221: u_int32 ifa;
! 222: {
! 223: struct ip_mreq mreq;
! 224:
! 225: mreq.imr_multiaddr.s_addr = grp;
! 226: mreq.imr_interface.s_addr = ifa;
! 227:
! 228: if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
! 229: (char *)&mreq, sizeof(mreq)) < 0)
! 230: log(LOG_WARNING, errno, "cannot join group %s on interface %s",
! 231: inet_fmt(grp, s1), inet_fmt(ifa, s2));
! 232: }
! 233:
! 234:
! 235: /*
! 236: * Leave a multicats grp group on local interface ifa.
! 237: */
! 238: void k_leave(socket, grp, ifa)
! 239: int socket;
! 240: u_int32 grp;
! 241: u_int32 ifa;
! 242: {
! 243: struct ip_mreq mreq;
! 244:
! 245: mreq.imr_multiaddr.s_addr = grp;
! 246: mreq.imr_interface.s_addr = ifa;
! 247:
! 248: if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
! 249: (char *)&mreq, sizeof(mreq)) < 0)
! 250: log(LOG_WARNING, errno, "cannot leave group %s on interface %s",
! 251: inet_fmt(grp, s1), inet_fmt(ifa, s2));
! 252: }
! 253:
! 254:
! 255: /*
! 256: * Add a virtual interface in the kernel.
! 257: */
! 258: void k_add_vif(socket, vifi, v)
! 259: int socket;
! 260: vifi_t vifi;
! 261: struct uvif *v;
! 262: {
! 263: struct vifctl vc;
! 264:
! 265: vc.vifc_vifi = vifi;
! 266: /* TODO: only for DVMRP tunnels?
! 267: vc.vifc_flags = v->uv_flags & VIFF_KERNEL_FLAGS;
! 268: */
! 269: vc.vifc_flags = v->uv_flags;
! 270: vc.vifc_threshold = v->uv_threshold;
! 271: vc.vifc_rate_limit = v->uv_rate_limit;
! 272: vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
! 273: vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
! 274:
! 275: if (setsockopt(socket, IPPROTO_IP, MRT_ADD_VIF,
! 276: (char *)&vc, sizeof(vc)) < 0)
! 277: log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF on vif %d", vifi);
! 278: }
! 279:
! 280:
! 281: /*
! 282: * Delete a virtual interface in the kernel.
! 283: */
! 284: void k_del_vif(socket, vifi)
! 285: int socket;
! 286: vifi_t vifi;
! 287: {
! 288: if (setsockopt(socket, IPPROTO_IP, MRT_DEL_VIF,
! 289: (char *)&vifi, sizeof(vifi)) < 0)
! 290: log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF on vif %d", vifi);
! 291: }
! 292:
! 293:
! 294: /*
! 295: * Delete all MFC entries for particular routing entry from the kernel.
! 296: */
! 297: int
! 298: k_del_mfc(socket, source, group)
! 299: int socket;
! 300: u_int32 source;
! 301: u_int32 group;
! 302: {
! 303: struct mfcctl mc;
! 304:
! 305: mc.mfcc_origin.s_addr = source;
! 306: mc.mfcc_mcastgrp.s_addr = group;
! 307:
! 308: if (setsockopt(socket, IPPROTO_IP, MRT_DEL_MFC, (char *)&mc,
! 309: sizeof(mc)) < 0) {
! 310: log(LOG_WARNING, errno, "setsockopt k_del_mfc");
! 311: return FALSE;
! 312: }
! 313:
! 314: IF_DEBUG(DEBUG_MFC)
! 315: log(LOG_DEBUG, 0, "Deleted MFC entry: src %s, grp %s",
! 316: inet_fmt(mc.mfcc_origin.s_addr, s1),
! 317: inet_fmt(mc.mfcc_mcastgrp.s_addr, s2));
! 318:
! 319: return(TRUE);
! 320: }
! 321:
! 322:
! 323: /*
! 324: * Install/modify a MFC entry in the kernel
! 325: */
! 326: int
! 327: k_chg_mfc(socket, source, group, iif, oifs)
! 328: int socket;
! 329: u_int32 source;
! 330: u_int32 group;
! 331: vifi_t iif;
! 332: vifbitmap_t oifs;
! 333: {
! 334: struct mfcctl mc;
! 335: vifi_t vifi;
! 336: struct uvif *v;
! 337:
! 338: mc.mfcc_origin.s_addr = source;
! 339: #ifdef OLD_KERNEL
! 340: mc.mfcc_originmas.s_addr = 0xffffffff; /* Got it from mrouted-3.9 */
! 341: #endif /* OLD_KERNEL */
! 342: mc.mfcc_mcastgrp.s_addr = group;
! 343: mc.mfcc_parent = iif;
! 344: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
! 345: if (VIFM_ISSET(vifi, oifs))
! 346: mc.mfcc_ttls[vifi] = v->uv_threshold;
! 347: else
! 348: mc.mfcc_ttls[vifi] = 0;
! 349: }
! 350:
! 351: if (setsockopt(socket, IPPROTO_IP, MRT_ADD_MFC, (char *)&mc,
! 352: sizeof(mc)) < 0) {
! 353: log(LOG_WARNING, errno,
! 354: "setsockopt MRT_ADD_MFC for source %s and group %s",
! 355: inet_fmt(source, s1), inet_fmt(group, s2));
! 356: return(FALSE);
! 357: }
! 358: return(TRUE);
! 359: }
! 360:
! 361:
! 362: /*
! 363: * Get packet counters for particular interface
! 364: */
! 365: /*
! 366: * XXX: TODO: currently not used, but keep just in case we need it later.
! 367: */
! 368: int k_get_vif_count(vifi, retval)
! 369: vifi_t vifi;
! 370: struct vif_count *retval;
! 371: {
! 372: struct sioc_vif_req vreq;
! 373:
! 374: vreq.vifi = vifi;
! 375: if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&vreq) < 0) {
! 376: log(LOG_WARNING, errno, "SIOCGETVIFCNT on vif %d", vifi);
! 377: retval->icount = retval->ocount = retval->ibytes =
! 378: retval->obytes = 0xffffffff;
! 379: return (1);
! 380: }
! 381: retval->icount = vreq.icount;
! 382: retval->ocount = vreq.ocount;
! 383: retval->ibytes = vreq.ibytes;
! 384: retval->obytes = vreq.obytes;
! 385: return (0);
! 386: }
! 387:
! 388:
! 389: /*
! 390: * Gets the number of packets, bytes, and number op packets arrived
! 391: * on wrong if in the kernel for particular (S,G) entry.
! 392: */
! 393: int
! 394: k_get_sg_cnt(socket, source, group, retval)
! 395: int socket; /* udp_socket */
! 396: u_int32 source;
! 397: u_int32 group;
! 398: struct sg_count *retval;
! 399: {
! 400: struct sioc_sg_req sgreq;
! 401:
! 402: sgreq.src.s_addr = source;
! 403: sgreq.grp.s_addr = group;
! 404: if ((ioctl(socket, SIOCGETSGCNT, (char *)&sgreq) < 0)
! 405: || (sgreq.wrong_if == 0xffffffff)) {
! 406: /* XXX: ipmulti-3.5 has bug in ip_mroute.c, get_sg_cnt():
! 407: * the return code is always 0, so this is why we need to check
! 408: * the wrong_if value.
! 409: */
! 410: log(LOG_WARNING, errno, "SIOCGETSGCNT on (%s %s)",
! 411: inet_fmt(source, s1), inet_fmt(group, s2));
! 412: retval->pktcnt = retval->bytecnt = retval->wrong_if = ~0;
! 413: return(1);
! 414: }
! 415: retval->pktcnt = sgreq.pktcnt;
! 416: retval->bytecnt = sgreq.bytecnt;
! 417: retval->wrong_if = sgreq.wrong_if;
! 418: return(0);
! 419: }
! 420:
! 421:
! 422:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>