ip_mroute.c revision 9209
11541Srgrimes/* 22531Swollman * IP multicast forwarding procedures 31541Srgrimes * 41541Srgrimes * Written by David Waitzman, BBN Labs, August 1988. 51541Srgrimes * Modified by Steve Deering, Stanford, February 1989. 62531Swollman * Modified by Mark J. Steiglitz, Stanford, May, 1991 72531Swollman * Modified by Van Jacobson, LBL, January 1993 82531Swollman * Modified by Ajit Thyagarajan, PARC, August 1993 99209Swollman * Modified by Bill Fenner, PARC, April 1995 101541Srgrimes * 119209Swollman * MROUTING Revision: 3.5 121541Srgrimes */ 131541Srgrimes 141541Srgrimes 151541Srgrimes#include <sys/param.h> 161549Srgrimes#include <sys/systm.h> 171541Srgrimes#include <sys/mbuf.h> 181541Srgrimes#include <sys/socket.h> 191541Srgrimes#include <sys/socketvar.h> 202531Swollman#include <sys/protosw.h> 212531Swollman#include <sys/errno.h> 221541Srgrimes#include <sys/time.h> 239209Swollman#include <sys/kernel.h> 242531Swollman#include <sys/ioctl.h> 252531Swollman#include <sys/syslog.h> 267684Sdg#include <sys/queue.h> 271541Srgrimes#include <net/if.h> 281541Srgrimes#include <net/route.h> 291541Srgrimes#include <netinet/in.h> 301541Srgrimes#include <netinet/in_systm.h> 311541Srgrimes#include <netinet/ip.h> 322531Swollman#include <netinet/ip_var.h> 331541Srgrimes#include <netinet/in_pcb.h> 341541Srgrimes#include <netinet/in_var.h> 351541Srgrimes#include <netinet/igmp.h> 361541Srgrimes#include <netinet/igmp_var.h> 371541Srgrimes#include <netinet/ip_mroute.h> 389209Swollman#include <netinet/udp.h> 391541Srgrimes 402531Swollman#ifndef NTOHL 412531Swollman#if BYTE_ORDER != BIG_ENDIAN 422531Swollman#define NTOHL(d) ((d) = ntohl((d))) 432531Swollman#define NTOHS(d) ((d) = ntohs((u_short)(d))) 442531Swollman#define HTONL(d) ((d) = htonl((d))) 452531Swollman#define HTONS(d) ((d) = htons((u_short)(d))) 462531Swollman#else 472531Swollman#define NTOHL(d) 482531Swollman#define NTOHS(d) 492531Swollman#define HTONL(d) 502531Swollman#define HTONS(d) 512531Swollman#endif 522531Swollman#endif 531541Srgrimes 549209Swollmanextern int rsvp_on; 559209Swollman 562531Swollman#ifndef MROUTING 572531Swollman/* 582531Swollman * Dummy routines and globals used when multicast routing is not compiled in. 592531Swollman */ 601541Srgrimes 619209Swollmanstruct socket *ip_mrouter = NULL; 622763Swollmanu_int ip_mrtproto = 0; 632763Swollmanstruct mrtstat mrtstat; 649209Swollmanu_int rsvpdebug = 0; 652531Swollman 662531Swollmanint 679209Swollman_ip_mrouter_set(cmd, so, m) 682531Swollman int cmd; 692531Swollman struct socket *so; 702531Swollman struct mbuf *m; 712531Swollman{ 722531Swollman return(EOPNOTSUPP); 732531Swollman} 742531Swollman 759209Swollmanint (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = _ip_mrouter_set; 762754Swollman 779209Swollman 782531Swollmanint 799209Swollman_ip_mrouter_get(cmd, so, m) 809209Swollman int cmd; 819209Swollman struct socket *so; 829209Swollman struct mbuf **m; 839209Swollman{ 849209Swollman return(EOPNOTSUPP); 859209Swollman} 869209Swollman 879209Swollmanint (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = _ip_mrouter_get; 889209Swollman 899209Swollmanint 902754Swollman_ip_mrouter_done() 912531Swollman{ 922531Swollman return(0); 932531Swollman} 942531Swollman 952754Swollmanint (*ip_mrouter_done)(void) = _ip_mrouter_done; 962754Swollman 972531Swollmanint 982754Swollman_ip_mforward(ip, ifp, m, imo) 992531Swollman struct ip *ip; 1002531Swollman struct ifnet *ifp; 1012531Swollman struct mbuf *m; 1022754Swollman struct ip_moptions *imo; 1032531Swollman{ 1042531Swollman return(0); 1052531Swollman} 1062754Swollman 1072754Swollmanint (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, 1082754Swollman struct ip_moptions *) = _ip_mforward; 1092754Swollman 1102754Swollmanint 1112754Swollman_mrt_ioctl(int req, caddr_t data, struct proc *p) 1122754Swollman{ 1132754Swollman return EOPNOTSUPP; 1142754Swollman} 1152754Swollman 1162754Swollmanint (*mrt_ioctl)(int, caddr_t, struct proc *) = _mrt_ioctl; 1172754Swollman 1189209Swollmanvoid 1199209Swollmanrsvp_input(m, iphlen) /* XXX must fixup manually */ 1209209Swollman struct mbuf *m; 1219209Swollman int iphlen; 1229209Swollman{ 1239209Swollman /* Can still get packets with rsvp_on = 0 if there is a local member 1249209Swollman * of the group to which the RSVP packet is addressed. But in this 1259209Swollman * case we want to throw the packet away. 1269209Swollman */ 1279209Swollman if (!rsvp_on) { 1289209Swollman m_freem(m); 1299209Swollman return; 1309209Swollman } 1319209Swollman 1329209Swollman if (ip_rsvpd != NULL) { 1339209Swollman if (rsvpdebug) 1349209Swollman printf("rsvp_input: Sending packet up old-style socket\n"); 1352754Swollman rip_input(m); 1369209Swollman return; 1379209Swollman } 1389209Swollman /* Drop the packet */ 1399209Swollman m_freem(m); 1402754Swollman} 1412754Swollman 1429209Swollmanvoid ipip_input(struct mbuf *m) { /* XXX must fixup manually */ 1439209Swollman rip_input(m); 1449209Swollman} 1459209Swollman 1462754Swollmanint (*legal_vif_num)(int) = 0; 1472754Swollman 1489209Swollman/* 1499209Swollman * This should never be called, since IP_MULTICAST_VIF should fail, but 1509209Swollman * just in case it does get called, the code a little lower in ip_output 1519209Swollman * will assign the packet a local address. 1529209Swollman */ 1539209Swollmanu_long 1549209Swollman_ip_mcast_src(int vifi) { return INADDR_ANY; } 1559209Swollmanu_long (*ip_mcast_src)(int) = _ip_mcast_src; 1569209Swollman 1579209Swollmanint 1589209Swollmanip_rsvp_vif_init(so, m) 1599209Swollman struct socket *so; 1609209Swollman struct mbuf *m; 1619209Swollman{ 1629209Swollman return(EINVAL); 1639209Swollman} 1649209Swollman 1659209Swollmanint 1669209Swollmanip_rsvp_vif_done(so, m) 1679209Swollman struct socket *so; 1689209Swollman struct mbuf *m; 1699209Swollman{ 1709209Swollman return(EINVAL); 1719209Swollman} 1729209Swollman 1739209Swollmanvoid 1749209Swollmanip_rsvp_force_done(so) 1759209Swollman struct socket *so; 1769209Swollman{ 1779209Swollman return; 1789209Swollman} 1799209Swollman 1807083Swollman#else /* MROUTING */ 1812531Swollman 1829209Swollman#define M_HASCL(m) ((m)->m_flags & M_EXT) 1839209Swollman 1842531Swollman#define INSIZ sizeof(struct in_addr) 1852531Swollman#define same(a1, a2) \ 1862531Swollman (bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0) 1872531Swollman 1882531Swollman#define MT_MRTABLE MT_RTABLE /* since nothing else uses it */ 1892531Swollman 1901541Srgrimes/* 1911541Srgrimes * Globals. All but ip_mrouter and ip_mrtproto could be static, 1921541Srgrimes * except for netstat or debugging purposes. 1931541Srgrimes */ 1942763Swollman#ifndef MROUTE_LKM 1952531Swollmanstruct socket *ip_mrouter = NULL; 1962763Swollmanstruct mrtstat mrtstat; 1972763Swollman 1982531Swollmanint ip_mrtproto = IGMP_DVMRP; /* for netstat only */ 1997083Swollman#else /* MROUTE_LKM */ 2002763Swollmanextern struct mrtstat mrtstat; 2012763Swollmanextern int ip_mrtproto; 2022763Swollman#endif 2031541Srgrimes 2042531Swollman#define NO_RTE_FOUND 0x1 2052531Swollman#define RTE_FOUND 0x2 2061541Srgrimes 2072531Swollmanstruct mbuf *mfctable[MFCTBLSIZ]; 2089209Swollmanu_char nexpire[MFCTBLSIZ]; 2092531Swollmanstruct vif viftable[MAXVIFS]; 2102531Swollmanu_int mrtdebug = 0; /* debug level */ 2119209Swollman#define DEBUG_MFC 0x02 2129209Swollman#define DEBUG_FORWARD 0x04 2139209Swollman#define DEBUG_EXPIRE 0x08 2149209Swollman#define DEBUG_XMIT 0x10 2152531Swollmanu_int tbfdebug = 0; /* tbf debug level */ 2169209Swollmanu_int rsvpdebug = 0; /* rsvp debug level */ 2172531Swollman 2189209Swollman#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */ 2199209Swollman#define UPCALL_EXPIRE 6 /* number of timeouts */ 2202531Swollman 2211541Srgrimes/* 2222531Swollman * Define the token bucket filter structures 2239209Swollman * tbftable -> each vif has one of these for storing info 2249209Swollman * qtable -> each interface has an associated queue of pkts 2252531Swollman */ 2262531Swollman 2272531Swollmanstruct tbf tbftable[MAXVIFS]; 2282531Swollmanstruct pkt_queue qtable[MAXVIFS][MAXQSIZE]; 2292531Swollman 2302531Swollman/* 2312531Swollman * 'Interfaces' associated with decapsulator (so we can tell 2322531Swollman * packets that went through it from ones that get reflected 2332531Swollman * by a broken gateway). These interfaces are never linked into 2342531Swollman * the system ifnet list & no routes point to them. I.e., packets 2352531Swollman * can't be sent this way. They only exist as a placeholder for 2362531Swollman * multicast source verification. 2372531Swollman */ 2382531Swollmanstruct ifnet multicast_decap_if[MAXVIFS]; 2392531Swollman 2402531Swollman#define ENCAP_TTL 64 2419209Swollman#define ENCAP_PROTO IPPROTO_IPIP /* 4 */ 2422531Swollman 2432531Swollman/* prototype IP hdr for encapsulated packets */ 2442531Swollmanstruct ip multicast_encap_iphdr = { 2452754Swollman#if BYTE_ORDER == LITTLE_ENDIAN 2462531Swollman sizeof(struct ip) >> 2, IPVERSION, 2472531Swollman#else 2482531Swollman IPVERSION, sizeof(struct ip) >> 2, 2492531Swollman#endif 2502531Swollman 0, /* tos */ 2512531Swollman sizeof(struct ip), /* total length */ 2522531Swollman 0, /* id */ 2532531Swollman 0, /* frag offset */ 2549209Swollman ENCAP_TTL, ENCAP_PROTO, 2552531Swollman 0, /* checksum */ 2562531Swollman}; 2572531Swollman 2582531Swollman/* 2591541Srgrimes * Private variables. 2601541Srgrimes */ 2612531Swollmanstatic vifi_t numvifs = 0; 2627083Swollmanstatic void (*encap_oldrawip)() = 0; 2639209Swollmanstatic int have_encap_tunnel = 0; 2641541Srgrimes 2651541Srgrimes/* 2669209Swollman * one-back cache used by ipip_input to locate a tunnel's vif 2672531Swollman * given a datagram's src ip address. 2682531Swollman */ 2692531Swollmanstatic u_long last_encap_src; 2702531Swollmanstatic struct vif *last_encap_vif; 2712531Swollman 2729209Swollmanstatic int get_sg_cnt(struct sioc_sg_req *); 2739209Swollmanstatic int get_vif_cnt(struct sioc_vif_req *); 2749209Swollmanint ip_mrouter_init(struct socket *, struct mbuf *); 2752531Swollmanstatic int add_vif(struct vifctl *); 2762531Swollmanstatic int del_vif(vifi_t *); 2772531Swollmanstatic int add_mfc(struct mfcctl *); 2789209Swollmanstatic int del_mfc(struct mfcctl *); 2799209Swollmanstatic int get_version(struct mbuf *); 2809209Swollmanstatic int get_assert(struct mbuf *); 2819209Swollmanstatic int set_assert(int *); 2829209Swollmanstatic void expire_upcalls(void *); 2839209Swollmanstatic int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *, 2849209Swollman vifi_t); 2852531Swollmanstatic void phyint_send(struct ip *, struct vif *, struct mbuf *); 2862531Swollmanstatic void encap_send(struct ip *, struct vif *, struct mbuf *); 2879209Swollmanstatic void tbf_control(struct vif *, struct mbuf *, struct ip *, u_long, 2882531Swollman struct ip_moptions *); 2899209Swollmanstatic void tbf_queue(struct vif *, struct mbuf *, struct ip *, struct ip_moptions *); 2909209Swollmanstatic void tbf_process_q(struct vif *); 2919209Swollmanstatic void tbf_dequeue(struct vif *, int); 2929209Swollmanstatic void tbf_reprocess_q(void *); 2939209Swollmanstatic int tbf_dq_sel(struct vif *, struct ip *); 2949209Swollmanstatic void tbf_send_packet(struct vif *, struct mbuf *, struct ip_moptions *); 2959209Swollmanstatic void tbf_update_tokens(struct vif *); 2962531Swollmanstatic int priority(struct vif *, struct ip *); 2979209Swollmanvoid multiencap_decap(struct mbuf *); 2982531Swollman 2992531Swollman/* 3009209Swollman * whether or not special PIM assert processing is enabled. 3018876Srgrimes */ 3029209Swollmanstatic int pim_assert; 3039209Swollman/* 3049209Swollman * Rate limit for assert notification messages, in usec 3059209Swollman */ 3069209Swollman#define ASSERT_MSG_TIME 3000000 3072531Swollman 3082531Swollman/* 3099209Swollman * Hash function for a source, group entry 3102531Swollman */ 3119209Swollman#define MFCHASH(a, g) MFCHASHMOD(((a) >> 20) ^ ((a) >> 10) ^ (a) ^ \ 3129209Swollman ((g) >> 20) ^ ((g) >> 10) ^ (g)) 3132531Swollman 3142531Swollman/* 3152531Swollman * Find a route for a given origin IP address and Multicast group address 3162531Swollman * Type of service parameter to be added in the future!!! 3172531Swollman */ 3189209Swollman 3192531Swollman#define MFCFIND(o, g, rt) { \ 3209209Swollman register struct mbuf *_mb_rt = mfctable[MFCHASH(o,g)]; \ 3219209Swollman register struct mfc *_rt = NULL; \ 3229209Swollman rt = NULL; \ 3232531Swollman ++mrtstat.mrts_mfc_lookups; \ 3249209Swollman while (_mb_rt) { \ 3259209Swollman _rt = mtod(_mb_rt, struct mfc *); \ 3269209Swollman if ((_rt->mfc_origin.s_addr == o) && \ 3279209Swollman (_rt->mfc_mcastgrp.s_addr == g) && \ 3289209Swollman (_mb_rt->m_act == NULL)) { \ 3299209Swollman rt = _rt; \ 3309209Swollman break; \ 3319209Swollman } \ 3329209Swollman _mb_rt = _mb_rt->m_next; \ 3339209Swollman } \ 3349209Swollman if (rt == NULL) { \ 3359209Swollman ++mrtstat.mrts_mfc_misses; \ 3369209Swollman } \ 3372531Swollman} 3382531Swollman 3392531Swollman 3402531Swollman/* 3412531Swollman * Macros to compute elapsed time efficiently 3422531Swollman * Borrowed from Van Jacobson's scheduling code 3432531Swollman */ 3442531Swollman#define TV_DELTA(a, b, delta) { \ 3452531Swollman register int xxs; \ 3462531Swollman \ 3472531Swollman delta = (a).tv_usec - (b).tv_usec; \ 3482531Swollman if ((xxs = (a).tv_sec - (b).tv_sec)) { \ 3492531Swollman switch (xxs) { \ 3502531Swollman case 2: \ 3512531Swollman delta += 1000000; \ 3522531Swollman /* fall through */ \ 3532531Swollman case 1: \ 3542531Swollman delta += 1000000; \ 3552531Swollman break; \ 3562531Swollman default: \ 3572531Swollman delta += (1000000 * xxs); \ 3582531Swollman } \ 3592531Swollman } \ 3602531Swollman} 3612531Swollman 3622531Swollman#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \ 3632531Swollman (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) 3642531Swollman 3659209Swollman#ifdef UPCALL_TIMING 3669209Swollmanu_long upcall_data[51]; 3679209Swollmanstatic void collate(struct timeval *); 3689209Swollman#endif /* UPCALL_TIMING */ 3699209Swollman 3709209Swollman 3712531Swollman/* 3729209Swollman * Handle MRT setsockopt commands to modify the multicast routing tables. 3731541Srgrimes */ 3741541Srgrimesint 3759209SwollmanX_ip_mrouter_set(cmd, so, m) 3762531Swollman int cmd; 3772531Swollman struct socket *so; 3782531Swollman struct mbuf *m; 3791541Srgrimes{ 3809209Swollman if (cmd != MRT_INIT && so != ip_mrouter) return EACCES; 3811541Srgrimes 3822531Swollman switch (cmd) { 3839209Swollman case MRT_INIT: return ip_mrouter_init(so, m); 3849209Swollman case MRT_DONE: return ip_mrouter_done(); 3859209Swollman case MRT_ADD_VIF: return add_vif (mtod(m, struct vifctl *)); 3869209Swollman case MRT_DEL_VIF: return del_vif (mtod(m, vifi_t *)); 3879209Swollman case MRT_ADD_MFC: return add_mfc (mtod(m, struct mfcctl *)); 3889209Swollman case MRT_DEL_MFC: return del_mfc (mtod(m, struct mfcctl *)); 3899209Swollman case MRT_ASSERT: return set_assert(mtod(m, int *)); 3902531Swollman default: return EOPNOTSUPP; 3912531Swollman } 3922531Swollman} 3931541Srgrimes 3942763Swollman#ifndef MROUTE_LKM 3959209Swollmanint (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = X_ip_mrouter_set; 3962763Swollman#endif 3971541Srgrimes 3982531Swollman/* 3999209Swollman * Handle MRT getsockopt commands 4009209Swollman */ 4019209Swollmanint 4029209SwollmanX_ip_mrouter_get(cmd, so, m) 4039209Swollman int cmd; 4049209Swollman struct socket *so; 4059209Swollman struct mbuf **m; 4069209Swollman{ 4079209Swollman struct mbuf *mb; 4089209Swollman 4099209Swollman if (so != ip_mrouter) return EACCES; 4109209Swollman 4119209Swollman *m = mb = m_get(M_WAIT, MT_SOOPTS); 4129209Swollman 4139209Swollman switch (cmd) { 4149209Swollman case MRT_VERSION: return get_version(mb); 4159209Swollman case MRT_ASSERT: return get_assert(mb); 4169209Swollman default: return EOPNOTSUPP; 4179209Swollman } 4189209Swollman} 4199209Swollman 4209209Swollman#ifndef MROUTE_LKM 4219209Swollmanint (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = X_ip_mrouter_get; 4229209Swollman#endif 4239209Swollman 4249209Swollman/* 4252531Swollman * Handle ioctl commands to obtain information from the cache 4262531Swollman */ 4272531Swollmanint 4282763SwollmanX_mrt_ioctl(cmd, data) 4292531Swollman int cmd; 4302531Swollman caddr_t data; 4312531Swollman{ 4322531Swollman int error = 0; 4331541Srgrimes 4342531Swollman switch (cmd) { 4359209Swollman case (SIOCGETVIFCNT): 4369209Swollman return (get_vif_cnt((struct sioc_vif_req *)data)); 4379209Swollman break; 4389209Swollman case (SIOCGETSGCNT): 4399209Swollman return (get_sg_cnt((struct sioc_sg_req *)data)); 4409209Swollman break; 4412531Swollman default: 4429209Swollman return (EINVAL); 4439209Swollman break; 4442531Swollman } 4452531Swollman return error; 4462531Swollman} 4471541Srgrimes 4482763Swollman#ifndef MROUTE_LKM 4492763Swollmanint (*mrt_ioctl)(int, caddr_t, struct proc *) = X_mrt_ioctl; 4502763Swollman#endif 4512754Swollman 4522531Swollman/* 4539209Swollman * returns the packet, byte, rpf-failure count for the source group provided 4542531Swollman */ 4559209Swollmanstatic int 4562531Swollmanget_sg_cnt(req) 4572531Swollman register struct sioc_sg_req *req; 4582531Swollman{ 4592531Swollman register struct mfc *rt; 4602531Swollman int s; 4611541Srgrimes 4622531Swollman s = splnet(); 4632531Swollman MFCFIND(req->src.s_addr, req->grp.s_addr, rt); 4642531Swollman splx(s); 4659209Swollman if (rt != NULL) { 4669209Swollman req->pktcnt = rt->mfc_pkt_cnt; 4679209Swollman req->bytecnt = rt->mfc_byte_cnt; 4689209Swollman req->wrong_if = rt->mfc_wrong_if; 4699209Swollman } else 4709209Swollman req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; 4711541Srgrimes 4722531Swollman return 0; 4732531Swollman} 4741541Srgrimes 4752531Swollman/* 4769209Swollman * returns the input and output packet and byte counts on the vif provided 4772531Swollman */ 4789209Swollmanstatic int 4792531Swollmanget_vif_cnt(req) 4802531Swollman register struct sioc_vif_req *req; 4812531Swollman{ 4822531Swollman register vifi_t vifi = req->vifi; 4831541Srgrimes 4849209Swollman if (vifi >= numvifs) return EINVAL; 4859209Swollman 4862531Swollman req->icount = viftable[vifi].v_pkt_in; 4872531Swollman req->ocount = viftable[vifi].v_pkt_out; 4889209Swollman req->ibytes = viftable[vifi].v_bytes_in; 4899209Swollman req->obytes = viftable[vifi].v_bytes_out; 4901541Srgrimes 4912531Swollman return 0; 4922531Swollman} 4932531Swollman 4941541Srgrimes/* 4951541Srgrimes * Enable multicast routing 4961541Srgrimes */ 4979209Swollmanint 4989209Swollmanip_mrouter_init(so, m) 4992531Swollman struct socket *so; 5009209Swollman struct mbuf *m; 5011541Srgrimes{ 5029209Swollman int *v; 5039209Swollman int i; 5049209Swollman 5059209Swollman if (mrtdebug) 5069209Swollman log(LOG_DEBUG,"ip_mrouter_init: so_type = %d, pr_protocol = %d", 5079209Swollman so->so_type, so->so_proto->pr_protocol); 5089209Swollman 5092531Swollman if (so->so_type != SOCK_RAW || 5102531Swollman so->so_proto->pr_protocol != IPPROTO_IGMP) return EOPNOTSUPP; 5111541Srgrimes 5129209Swollman if (!m || (m->m_len != sizeof(int *))) 5139209Swollman return ENOPROTOOPT; 5149209Swollman 5159209Swollman v = mtod(m, int *); 5169209Swollman if (*v != 1) 5179209Swollman return ENOPROTOOPT; 5189209Swollman 5192531Swollman if (ip_mrouter != NULL) return EADDRINUSE; 5201541Srgrimes 5212531Swollman ip_mrouter = so; 5221541Srgrimes 5239209Swollman bzero((caddr_t)mfctable, sizeof(mfctable)); 5249209Swollman bzero((caddr_t)nexpire, sizeof(nexpire)); 5259209Swollman 5269209Swollman pim_assert = 0; 5279209Swollman 5289209Swollman timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); 5299209Swollman 5302531Swollman if (mrtdebug) 5319209Swollman log(LOG_DEBUG, "ip_mrouter_init"); 5322531Swollman 5332531Swollman return 0; 5341541Srgrimes} 5351541Srgrimes 5361541Srgrimes/* 5371541Srgrimes * Disable multicast routing 5381541Srgrimes */ 5391541Srgrimesint 5402763SwollmanX_ip_mrouter_done() 5411541Srgrimes{ 5422531Swollman vifi_t vifi; 5432531Swollman int i; 5442531Swollman struct ifnet *ifp; 5452531Swollman struct ifreq ifr; 5462531Swollman struct mbuf *mb_rt; 5479209Swollman struct mfc *rt; 5482531Swollman struct mbuf *m; 5492531Swollman struct rtdetq *rte; 5502531Swollman int s; 5511541Srgrimes 5522531Swollman s = splnet(); 5531541Srgrimes 5542531Swollman /* 5552531Swollman * For each phyint in use, disable promiscuous reception of all IP 5562531Swollman * multicasts. 5572531Swollman */ 5582531Swollman for (vifi = 0; vifi < numvifs; vifi++) { 5592531Swollman if (viftable[vifi].v_lcl_addr.s_addr != 0 && 5602531Swollman !(viftable[vifi].v_flags & VIFF_TUNNEL)) { 5612531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; 5622531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr 5632531Swollman = INADDR_ANY; 5642531Swollman ifp = viftable[vifi].v_ifp; 5652531Swollman (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); 5662531Swollman } 5672531Swollman } 5682531Swollman bzero((caddr_t)qtable, sizeof(qtable)); 5692531Swollman bzero((caddr_t)tbftable, sizeof(tbftable)); 5702531Swollman bzero((caddr_t)viftable, sizeof(viftable)); 5712531Swollman numvifs = 0; 5729209Swollman pim_assert = 0; 5732531Swollman 5749209Swollman untimeout(expire_upcalls, (caddr_t)NULL); 5759209Swollman 5762531Swollman /* 5779209Swollman * Free all multicast forwarding cache entries. 5782531Swollman */ 5799209Swollman for (i = 0; i < MFCTBLSIZ; i++) { 5809209Swollman mb_rt = mfctable[i]; 5819209Swollman while (mb_rt) { 5829209Swollman if (mb_rt->m_act != NULL) { 5839209Swollman while (mb_rt->m_act) { 5849209Swollman m = mb_rt->m_act; 5859209Swollman mb_rt->m_act = m->m_act; 5869209Swollman rte = mtod(m, struct rtdetq *); 5879209Swollman m_freem(rte->m); 5889209Swollman m_free(m); 5891541Srgrimes } 5902531Swollman } 5919209Swollman mb_rt = m_free(mb_rt); 5921541Srgrimes } 5939209Swollman } 5941541Srgrimes 5952531Swollman bzero((caddr_t)mfctable, sizeof(mfctable)); 5961541Srgrimes 5972531Swollman /* 5982531Swollman * Reset de-encapsulation cache 5992531Swollman */ 6002531Swollman last_encap_src = NULL; 6012531Swollman last_encap_vif = NULL; 6029209Swollman have_encap_tunnel = 0; 6039209Swollman 6042531Swollman ip_mrouter = NULL; 6052531Swollman 6062531Swollman splx(s); 6072531Swollman 6082531Swollman if (mrtdebug) 6099209Swollman log(LOG_DEBUG, "ip_mrouter_done"); 6102531Swollman 6112531Swollman return 0; 6121541Srgrimes} 6131541Srgrimes 6142763Swollman#ifndef MROUTE_LKM 6152763Swollmanint (*ip_mrouter_done)(void) = X_ip_mrouter_done; 6162763Swollman#endif 6172754Swollman 6189209Swollmanstatic int 6199209Swollmanget_version(mb) 6209209Swollman struct mbuf *mb; 6219209Swollman{ 6229209Swollman int *v; 6239209Swollman 6249209Swollman v = mtod(mb, int *); 6259209Swollman 6269209Swollman *v = 0x0305; /* XXX !!!! */ 6279209Swollman mb->m_len = sizeof(int); 6289209Swollman 6299209Swollman return 0; 6309209Swollman} 6319209Swollman 6321541Srgrimes/* 6339209Swollman * Set PIM assert processing global 6349209Swollman */ 6359209Swollmanstatic int 6369209Swollmanset_assert(i) 6379209Swollman int *i; 6389209Swollman{ 6399209Swollman if ((*i != 1) && (*i != 0)) 6409209Swollman return EINVAL; 6419209Swollman 6429209Swollman pim_assert = *i; 6439209Swollman 6449209Swollman return 0; 6459209Swollman} 6469209Swollman 6479209Swollman/* 6489209Swollman * Get PIM assert processing global 6499209Swollman */ 6509209Swollmanstatic int 6519209Swollmanget_assert(m) 6529209Swollman struct mbuf *m; 6539209Swollman{ 6549209Swollman int *i; 6559209Swollman 6569209Swollman i = mtod(m, int *); 6579209Swollman 6589209Swollman *i = pim_assert; 6599209Swollman 6609209Swollman return 0; 6619209Swollman} 6629209Swollman 6639209Swollman/* 6641541Srgrimes * Add a vif to the vif table 6651541Srgrimes */ 6661541Srgrimesstatic int 6671541Srgrimesadd_vif(vifcp) 6682531Swollman register struct vifctl *vifcp; 6691541Srgrimes{ 6702531Swollman register struct vif *vifp = viftable + vifcp->vifc_vifi; 6713747Swollman static struct sockaddr_in sin = {sizeof sin, AF_INET}; 6722531Swollman struct ifaddr *ifa; 6732531Swollman struct ifnet *ifp; 6742531Swollman struct ifreq ifr; 6752531Swollman int error, s; 6762531Swollman struct tbf *v_tbf = tbftable + vifcp->vifc_vifi; 6771541Srgrimes 6782531Swollman if (vifcp->vifc_vifi >= MAXVIFS) return EINVAL; 6792531Swollman if (vifp->v_lcl_addr.s_addr != 0) return EADDRINUSE; 6801541Srgrimes 6812531Swollman /* Find the interface with an address in AF_INET family */ 6822531Swollman sin.sin_addr = vifcp->vifc_lcl_addr; 6832531Swollman ifa = ifa_ifwithaddr((struct sockaddr *)&sin); 6842531Swollman if (ifa == 0) return EADDRNOTAVAIL; 6852531Swollman ifp = ifa->ifa_ifp; 6861541Srgrimes 6872531Swollman if (vifcp->vifc_flags & VIFF_TUNNEL) { 6882531Swollman if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) { 6899209Swollman /* 6909209Swollman * An encapsulating tunnel is wanted. Tell ipip_input() to 6919209Swollman * start paying attention to encapsulated packets. 6929209Swollman */ 6939209Swollman if (have_encap_tunnel == 0) { 6949209Swollman have_encap_tunnel = 1; 6959209Swollman for (s = 0; s < MAXVIFS; ++s) { 6969209Swollman multicast_decap_if[s].if_name = "mdecap"; 6979209Swollman multicast_decap_if[s].if_unit = s; 6989209Swollman } 6991541Srgrimes } 7009209Swollman /* 7019209Swollman * Set interface to fake encapsulator interface 7029209Swollman */ 7039209Swollman ifp = &multicast_decap_if[vifcp->vifc_vifi]; 7049209Swollman /* 7059209Swollman * Prepare cached route entry 7069209Swollman */ 7079209Swollman bzero(&vifp->v_route, sizeof(vifp->v_route)); 7082531Swollman } else { 7099209Swollman log(LOG_ERR, "Source routed tunnels not supported."); 7109209Swollman return EOPNOTSUPP; 7111541Srgrimes } 7122531Swollman } else { 7132531Swollman /* Make sure the interface supports multicast */ 7142531Swollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 7152531Swollman return EOPNOTSUPP; 7161541Srgrimes 7172531Swollman /* Enable promiscuous reception of all IP multicasts from the if */ 7182531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; 7192531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY; 7202531Swollman s = splnet(); 7212531Swollman error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); 7222531Swollman splx(s); 7232531Swollman if (error) 7242531Swollman return error; 7252531Swollman } 7261541Srgrimes 7272531Swollman s = splnet(); 7282531Swollman /* define parameters for the tbf structure */ 7292531Swollman vifp->v_tbf = v_tbf; 7302531Swollman vifp->v_tbf->q_len = 0; 7312531Swollman vifp->v_tbf->n_tok = 0; 7322531Swollman vifp->v_tbf->last_pkt_t = 0; 7331541Srgrimes 7342531Swollman vifp->v_flags = vifcp->vifc_flags; 7352531Swollman vifp->v_threshold = vifcp->vifc_threshold; 7362531Swollman vifp->v_lcl_addr = vifcp->vifc_lcl_addr; 7372531Swollman vifp->v_rmt_addr = vifcp->vifc_rmt_addr; 7382531Swollman vifp->v_ifp = ifp; 7392531Swollman vifp->v_rate_limit= vifcp->vifc_rate_limit; 7409209Swollman vifp->v_rsvp_on = 0; 7419209Swollman vifp->v_rsvpd = NULL; 7422531Swollman /* initialize per vif pkt counters */ 7432531Swollman vifp->v_pkt_in = 0; 7442531Swollman vifp->v_pkt_out = 0; 7459209Swollman vifp->v_bytes_in = 0; 7469209Swollman vifp->v_bytes_out = 0; 7472531Swollman splx(s); 7482531Swollman 7492531Swollman /* Adjust numvifs up if the vifi is higher than numvifs */ 7502531Swollman if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1; 7512531Swollman 7522531Swollman if (mrtdebug) 7539209Swollman log(LOG_DEBUG, "add_vif #%d, lcladdr %x, %s %x, thresh %x, rate %d", 7549209Swollman vifcp->vifc_vifi, 7552531Swollman ntohl(vifcp->vifc_lcl_addr.s_addr), 7562531Swollman (vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask", 7572531Swollman ntohl(vifcp->vifc_rmt_addr.s_addr), 7582531Swollman vifcp->vifc_threshold, 7599209Swollman vifcp->vifc_rate_limit); 7602531Swollman 7612531Swollman return 0; 7621541Srgrimes} 7631541Srgrimes 7641541Srgrimes/* 7651541Srgrimes * Delete a vif from the vif table 7661541Srgrimes */ 7671541Srgrimesstatic int 7681541Srgrimesdel_vif(vifip) 7692531Swollman vifi_t *vifip; 7701541Srgrimes{ 7712531Swollman register struct vif *vifp = viftable + *vifip; 7722531Swollman register vifi_t vifi; 7732531Swollman struct ifnet *ifp; 7742531Swollman struct ifreq ifr; 7752531Swollman int s; 7761541Srgrimes 7772531Swollman if (*vifip >= numvifs) return EINVAL; 7782531Swollman if (vifp->v_lcl_addr.s_addr == 0) return EADDRNOTAVAIL; 7791541Srgrimes 7802531Swollman s = splnet(); 7811541Srgrimes 7822531Swollman if (!(vifp->v_flags & VIFF_TUNNEL)) { 7832531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; 7842531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY; 7852531Swollman ifp = vifp->v_ifp; 7862531Swollman (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); 7872531Swollman } 7881541Srgrimes 7892531Swollman if (vifp == last_encap_vif) { 7902531Swollman last_encap_vif = 0; 7912531Swollman last_encap_src = 0; 7922531Swollman } 7931541Srgrimes 7942531Swollman bzero((caddr_t)qtable[*vifip], 7952531Swollman sizeof(qtable[*vifip])); 7962531Swollman bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf))); 7972531Swollman bzero((caddr_t)vifp, sizeof (*vifp)); 7981541Srgrimes 7992531Swollman /* Adjust numvifs down */ 8002531Swollman for (vifi = numvifs; vifi > 0; vifi--) 8012531Swollman if (viftable[vifi-1].v_lcl_addr.s_addr != 0) break; 8022531Swollman numvifs = vifi; 8032531Swollman 8042531Swollman splx(s); 8052531Swollman 8062531Swollman if (mrtdebug) 8079209Swollman log(LOG_DEBUG, "del_vif %d, numvifs %d", *vifip, numvifs); 8082531Swollman 8092531Swollman return 0; 8101541Srgrimes} 8111541Srgrimes 8121541Srgrimes/* 8132531Swollman * Add an mfc entry 8141541Srgrimes */ 8151541Srgrimesstatic int 8162531Swollmanadd_mfc(mfccp) 8172531Swollman struct mfcctl *mfccp; 8181541Srgrimes{ 8192531Swollman struct mfc *rt; 8202531Swollman register struct mbuf *mb_rt; 8212531Swollman u_long hash; 8222531Swollman struct mbuf *mb_ntry; 8232531Swollman struct rtdetq *rte; 8242531Swollman register u_short nstl; 8252531Swollman int s; 8262531Swollman int i; 8271541Srgrimes 8289209Swollman MFCFIND(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr, rt); 8291541Srgrimes 8302531Swollman /* If an entry already exists, just update the fields */ 8312531Swollman if (rt) { 8329209Swollman if (mrtdebug & DEBUG_MFC) 8339209Swollman log(LOG_DEBUG,"add_mfc update o %x g %x p %x", 8342531Swollman ntohl(mfccp->mfcc_origin.s_addr), 8352531Swollman ntohl(mfccp->mfcc_mcastgrp.s_addr), 8362531Swollman mfccp->mfcc_parent); 8371541Srgrimes 8381541Srgrimes s = splnet(); 8392531Swollman rt->mfc_parent = mfccp->mfcc_parent; 8402531Swollman for (i = 0; i < numvifs; i++) 8419209Swollman rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 8422531Swollman splx(s); 8432531Swollman return 0; 8442531Swollman } 8451541Srgrimes 8469209Swollman /* 8472531Swollman * Find the entry for which the upcall was made and update 8482531Swollman */ 8492531Swollman s = splnet(); 8509209Swollman hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); 8519209Swollman for (mb_rt = mfctable[hash], nstl = 0; mb_rt; mb_rt = mb_rt->m_next) { 8521541Srgrimes 8532531Swollman rt = mtod(mb_rt, struct mfc *); 8549209Swollman if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && 8552531Swollman (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) && 8562531Swollman (mb_rt->m_act != NULL)) { 8579209Swollman 8589209Swollman if (nstl++) 8599209Swollman log(LOG_ERR, "add_mfc %s o %x g %x p %x dbx %x", 8609209Swollman "multiple kernel entries", 8619209Swollman ntohl(mfccp->mfcc_origin.s_addr), 8629209Swollman ntohl(mfccp->mfcc_mcastgrp.s_addr), 8639209Swollman mfccp->mfcc_parent, mb_rt->m_act); 8641541Srgrimes 8659209Swollman if (mrtdebug & DEBUG_MFC) 8669209Swollman log(LOG_DEBUG,"add_mfc o %x g %x p %x dbg %x", 8679209Swollman ntohl(mfccp->mfcc_origin.s_addr), 8689209Swollman ntohl(mfccp->mfcc_mcastgrp.s_addr), 8699209Swollman mfccp->mfcc_parent, mb_rt->m_act); 8701541Srgrimes 8719209Swollman rt->mfc_origin = mfccp->mfcc_origin; 8729209Swollman rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; 8739209Swollman rt->mfc_parent = mfccp->mfcc_parent; 8749209Swollman for (i = 0; i < numvifs; i++) 8759209Swollman rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 8769209Swollman /* initialize pkt counters per src-grp */ 8779209Swollman rt->mfc_pkt_cnt = 0; 8789209Swollman rt->mfc_byte_cnt = 0; 8799209Swollman rt->mfc_wrong_if = 0; 8809209Swollman rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; 8812531Swollman 8829209Swollman rt->mfc_expire = 0; /* Don't clean this guy up */ 8839209Swollman nexpire[hash]--; 8842531Swollman 8852531Swollman /* free packets Qed at the end of this entry */ 8862531Swollman while (mb_rt->m_act) { 8872531Swollman mb_ntry = mb_rt->m_act; 8882531Swollman rte = mtod(mb_ntry, struct rtdetq *); 8899209Swollman/* #ifdef RSVP_ISI */ 8909209Swollman ip_mdq(rte->m, rte->ifp, rt, -1); 8919209Swollman/* #endif */ 8922531Swollman mb_rt->m_act = mb_ntry->m_act; 8932531Swollman m_freem(rte->m); 8949209Swollman#ifdef UPCALL_TIMING 8959209Swollman collate(&(rte->t)); 8969209Swollman#endif /* UPCALL_TIMING */ 8972531Swollman m_free(mb_ntry); 8982531Swollman } 8991541Srgrimes } 9002531Swollman } 9011541Srgrimes 9022531Swollman /* 9032531Swollman * It is possible that an entry is being inserted without an upcall 9042531Swollman */ 9052531Swollman if (nstl == 0) { 9069209Swollman if (mrtdebug & DEBUG_MFC) 9079209Swollman log(LOG_DEBUG,"add_mfc no upcall h %d o %x g %x p %x", 9082531Swollman hash, ntohl(mfccp->mfcc_origin.s_addr), 9092531Swollman ntohl(mfccp->mfcc_mcastgrp.s_addr), 9102531Swollman mfccp->mfcc_parent); 9119209Swollman 9129209Swollman for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) { 9139209Swollman 9142531Swollman rt = mtod(mb_rt, struct mfc *); 9159209Swollman if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && 9162531Swollman (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) { 9171541Srgrimes 9182531Swollman rt->mfc_origin = mfccp->mfcc_origin; 9192531Swollman rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; 9202531Swollman rt->mfc_parent = mfccp->mfcc_parent; 9212531Swollman for (i = 0; i < numvifs; i++) 9229209Swollman rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 9232531Swollman /* initialize pkt counters per src-grp */ 9242531Swollman rt->mfc_pkt_cnt = 0; 9259209Swollman rt->mfc_byte_cnt = 0; 9269209Swollman rt->mfc_wrong_if = 0; 9279209Swollman rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; 9289209Swollman if (rt->mfc_expire) 9299209Swollman nexpire[hash]--; 9309209Swollman rt->mfc_expire = 0; 9312531Swollman } 9322531Swollman } 9332531Swollman if (mb_rt == NULL) { 9342531Swollman /* no upcall, so make a new entry */ 9352531Swollman MGET(mb_rt, M_DONTWAIT, MT_MRTABLE); 9362531Swollman if (mb_rt == NULL) { 9372531Swollman splx(s); 9382531Swollman return ENOBUFS; 9392531Swollman } 9409209Swollman 9412531Swollman rt = mtod(mb_rt, struct mfc *); 9429209Swollman 9432531Swollman /* insert new entry at head of hash chain */ 9442531Swollman rt->mfc_origin = mfccp->mfcc_origin; 9452531Swollman rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; 9462531Swollman rt->mfc_parent = mfccp->mfcc_parent; 9472531Swollman for (i = 0; i < numvifs; i++) 9489209Swollman rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 9492531Swollman /* initialize pkt counters per src-grp */ 9502531Swollman rt->mfc_pkt_cnt = 0; 9519209Swollman rt->mfc_byte_cnt = 0; 9529209Swollman rt->mfc_wrong_if = 0; 9539209Swollman rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; 9549209Swollman rt->mfc_expire = 0; 9559209Swollman 9562531Swollman /* link into table */ 9572531Swollman mb_rt->m_next = mfctable[hash]; 9582531Swollman mfctable[hash] = mb_rt; 9592531Swollman mb_rt->m_act = NULL; 9602531Swollman } 9612531Swollman } 9622531Swollman splx(s); 9632531Swollman return 0; 9641541Srgrimes} 9651541Srgrimes 9669209Swollman#ifdef UPCALL_TIMING 9671541Srgrimes/* 9689209Swollman * collect delay statistics on the upcalls 9699209Swollman */ 9709209Swollmanstatic void collate(t) 9719209Swollmanregister struct timeval *t; 9729209Swollman{ 9739209Swollman register u_long d; 9749209Swollman register struct timeval tp; 9759209Swollman register u_long delta; 9769209Swollman 9779209Swollman GET_TIME(tp); 9789209Swollman 9799209Swollman if (TV_LT(*t, tp)) 9809209Swollman { 9819209Swollman TV_DELTA(tp, *t, delta); 9829209Swollman 9839209Swollman d = delta >> 10; 9849209Swollman if (d > 50) 9859209Swollman d = 50; 9869209Swollman 9879209Swollman ++upcall_data[d]; 9889209Swollman } 9899209Swollman} 9909209Swollman#endif /* UPCALL_TIMING */ 9919209Swollman 9929209Swollman/* 9932531Swollman * Delete an mfc entry 9941541Srgrimes */ 9951541Srgrimesstatic int 9962531Swollmandel_mfc(mfccp) 9979209Swollman struct mfcctl *mfccp; 9981541Srgrimes{ 9992531Swollman struct in_addr origin; 10002531Swollman struct in_addr mcastgrp; 10012531Swollman struct mfc *rt; 10022531Swollman struct mbuf *mb_rt; 10039209Swollman struct mbuf **nptr; 10042531Swollman u_long hash; 10059209Swollman int s, i; 10061541Srgrimes 10072531Swollman origin = mfccp->mfcc_origin; 10082531Swollman mcastgrp = mfccp->mfcc_mcastgrp; 10099209Swollman hash = MFCHASH(origin.s_addr, mcastgrp.s_addr); 10101541Srgrimes 10119209Swollman if (mrtdebug & DEBUG_MFC) 10129209Swollman log(LOG_DEBUG,"del_mfc orig %x mcastgrp %x", 10132531Swollman ntohl(origin.s_addr), ntohl(mcastgrp.s_addr)); 10141541Srgrimes 10159209Swollman s = splnet(); 10169209Swollman 10179209Swollman nptr = &mfctable[hash]; 10189209Swollman while ((mb_rt = *nptr) != NULL) { 10192531Swollman rt = mtod(mb_rt, struct mfc *); 10202531Swollman if (origin.s_addr == rt->mfc_origin.s_addr && 10212531Swollman mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr && 10222531Swollman mb_rt->m_act == NULL) 10232531Swollman break; 10249209Swollman 10259209Swollman nptr = &mb_rt->m_next; 10262531Swollman } 10272531Swollman if (mb_rt == NULL) { 10289209Swollman splx(s); 10299209Swollman return EADDRNOTAVAIL; 10302531Swollman } 10311541Srgrimes 10329209Swollman MFREE(mb_rt, *nptr); 10331541Srgrimes 10342531Swollman splx(s); 10352531Swollman 10362531Swollman return 0; 10371541Srgrimes} 10381541Srgrimes 10391541Srgrimes/* 10409209Swollman * Send a message to mrouted on the multicast routing socket 10419209Swollman */ 10429209Swollmanstatic int 10439209Swollmansocket_send(s, mm, src) 10449209Swollman struct socket *s; 10459209Swollman struct mbuf *mm; 10469209Swollman struct sockaddr_in *src; 10479209Swollman{ 10489209Swollman if (s) { 10499209Swollman if (sbappendaddr(&s->so_rcv, 10509209Swollman (struct sockaddr *)src, 10519209Swollman mm, (struct mbuf *)0) != 0) { 10529209Swollman sorwakeup(s); 10539209Swollman return 0; 10549209Swollman } 10559209Swollman } 10569209Swollman m_freem(mm); 10579209Swollman return -1; 10589209Swollman} 10599209Swollman 10609209Swollman/* 10612531Swollman * IP multicast forwarding function. This function assumes that the packet 10622531Swollman * pointed to by "ip" has arrived on (or is about to be sent to) the interface 10632531Swollman * pointed to by "ifp", and the packet is to be relayed to other networks 10642531Swollman * that have members of the packet's destination IP multicast group. 10652531Swollman * 10669209Swollman * The packet is returned unscathed to the caller, unless it is 10679209Swollman * erroneous, in which case a non-zero return value tells the caller to 10682531Swollman * discard it. 10691541Srgrimes */ 10702531Swollman 10712531Swollman#define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */ 10722531Swollman#define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */ 10732531Swollman 10742531Swollmanint 10752763SwollmanX_ip_mforward(ip, ifp, m, imo) 10762531Swollman register struct ip *ip; 10772531Swollman struct ifnet *ifp; 10782754Swollman struct mbuf *m; 10792531Swollman struct ip_moptions *imo; 10801541Srgrimes{ 10819209Swollman register struct mfc *rt = 0; /* XXX uninit warning */ 10822531Swollman register u_char *ipoptions; 10832531Swollman static struct sockproto k_igmpproto = { AF_INET, IPPROTO_IGMP }; 10843747Swollman static struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; 10859209Swollman static int srctun = 0; 10862531Swollman register struct mbuf *mm; 10872531Swollman int s; 10889209Swollman vifi_t vifi; 10899209Swollman struct vif *vifp; 10901541Srgrimes 10919209Swollman if (mrtdebug & DEBUG_FORWARD) 10929209Swollman log(LOG_DEBUG, "ip_mforward: src %x, dst %x, ifp %x", 10939209Swollman ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), ifp); 10941541Srgrimes 10952531Swollman if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 || 10962531Swollman (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) { 10972531Swollman /* 10989209Swollman * Packet arrived via a physical interface or 10999209Swollman * an encapsulated tunnel. 11002531Swollman */ 11012531Swollman } else { 11022531Swollman /* 11032531Swollman * Packet arrived through a source-route tunnel. 11049209Swollman * Source-route tunnels are no longer supported. 11052531Swollman */ 11069209Swollman if ((srctun++ % 1000) == 0) 11079209Swollman log(LOG_ERR, "ip_mforward: received source-routed packet from %x", 11089209Swollman ntohl(ip->ip_src.s_addr)); 11098876Srgrimes 11109209Swollman return 1; 11119209Swollman } 11129209Swollman 11139209Swollman if ((imo) && ((vifi = imo->imo_multicast_vif) < numvifs)) { 11149209Swollman if (ip->ip_ttl < 255) 11159209Swollman ip->ip_ttl++; /* compensate for -1 in *_send routines */ 11169209Swollman if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { 11179209Swollman vifp = viftable + vifi; 11189209Swollman printf("Sending IPPROTO_RSVP from %x to %x on vif %d (%s%s%d)\n", 11199209Swollman ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), vifi, 11209209Swollman (vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "", 11219209Swollman vifp->v_ifp->if_name, vifp->v_ifp->if_unit); 11222531Swollman } 11239209Swollman return (ip_mdq(m, ifp, rt, vifi)); 11242531Swollman } 11259209Swollman if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { 11269209Swollman printf("Warning: IPPROTO_RSVP from %x to %x without vif option\n", 11279209Swollman ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr)); 11289209Swollman } 11292531Swollman 11302531Swollman /* 11312531Swollman * Don't forward a packet with time-to-live of zero or one, 11322531Swollman * or a packet destined to a local-only group. 11332531Swollman */ 11342531Swollman if (ip->ip_ttl <= 1 || 11352531Swollman ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP) 11369209Swollman return 0; 11372531Swollman 11382531Swollman /* 11392531Swollman * Determine forwarding vifs from the forwarding cache table 11402531Swollman */ 11412531Swollman s = splnet(); 11422531Swollman MFCFIND(ip->ip_src.s_addr, ip->ip_dst.s_addr, rt); 11432531Swollman 11442531Swollman /* Entry exists, so forward if necessary */ 11452531Swollman if (rt != NULL) { 11461541Srgrimes splx(s); 11479209Swollman return (ip_mdq(m, ifp, rt, -1)); 11489209Swollman } else { 11492531Swollman /* 11502531Swollman * If we don't have a route for packet's origin, 11512531Swollman * Make a copy of the packet & 11522531Swollman * send message to routing daemon 11532531Swollman */ 11542531Swollman 11552531Swollman register struct mbuf *mb_rt; 11562531Swollman register struct mbuf *mb_ntry; 11572531Swollman register struct mbuf *mb0; 11582531Swollman register struct rtdetq *rte; 11592531Swollman register struct mbuf *rte_m; 11602531Swollman register u_long hash; 11619209Swollman register int npkts; 11629209Swollman#ifdef UPCALL_TIMING 11639209Swollman struct timeval tp; 11642531Swollman 11659209Swollman GET_TIME(tp); 11669209Swollman#endif 11679209Swollman 11682531Swollman mrtstat.mrts_no_route++; 11699209Swollman if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC)) 11709209Swollman log(LOG_DEBUG, "ip_mforward: no rte s %x g %x", 11712531Swollman ntohl(ip->ip_src.s_addr), 11722531Swollman ntohl(ip->ip_dst.s_addr)); 11732531Swollman 11749209Swollman /* 11759209Swollman * Allocate mbufs early so that we don't do extra work if we are 11769209Swollman * just going to fail anyway. 11779209Swollman */ 11789209Swollman MGET(mb_ntry, M_DONTWAIT, MT_DATA); 11799209Swollman if (mb_ntry == NULL) { 11809209Swollman splx(s); 11819209Swollman return ENOBUFS; 11829209Swollman } 11839209Swollman mb0 = m_copy(m, 0, M_COPYALL); 11849209Swollman if (mb0 == NULL) { 11859209Swollman m_free(mb_ntry); 11869209Swollman splx(s); 11879209Swollman return ENOBUFS; 11889209Swollman } 11899209Swollman 11902531Swollman /* is there an upcall waiting for this packet? */ 11919209Swollman hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr); 11922531Swollman for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) { 11932531Swollman rt = mtod(mb_rt, struct mfc *); 11949209Swollman if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) && 11952531Swollman (ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) && 11962531Swollman (mb_rt->m_act != NULL)) 11972531Swollman break; 11982531Swollman } 11992531Swollman 12002531Swollman if (mb_rt == NULL) { 12019209Swollman int hlen = ip->ip_hl << 2; 12029209Swollman int i; 12039209Swollman struct igmpmsg *im; 12049209Swollman 12052531Swollman /* no upcall, so make a new entry */ 12062531Swollman MGET(mb_rt, M_DONTWAIT, MT_MRTABLE); 12072531Swollman if (mb_rt == NULL) { 12089209Swollman m_free(mb_ntry); 12099209Swollman m_free(mb0); 12102531Swollman splx(s); 12112531Swollman return ENOBUFS; 12122531Swollman } 12139209Swollman /* Make a copy of the header to send to the user level process */ 12149209Swollman mm = m_copy(m, 0, hlen); 12159209Swollman if (mm && (M_HASCL(mm) || mm->m_len < hlen)) 12169209Swollman mm = m_pullup(mm, hlen); 12179209Swollman if (mm == NULL) { 12189209Swollman m_free(mb_ntry); 12199209Swollman m_free(mb0); 12209209Swollman m_free(mb_rt); 12219209Swollman splx(s); 12229209Swollman return ENOBUFS; 12239209Swollman } 12242531Swollman 12259209Swollman /* 12269209Swollman * Send message to routing daemon to install 12279209Swollman * a route into the kernel table 12289209Swollman */ 12299209Swollman k_igmpsrc.sin_addr = ip->ip_src; 12309209Swollman 12319209Swollman im = mtod(mm, struct igmpmsg *); 12329209Swollman im->im_msgtype = IGMPMSG_NOCACHE; 12339209Swollman im->im_mbz = 0; 12349209Swollman 12359209Swollman mrtstat.mrts_upcalls++; 12369209Swollman 12379209Swollman if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) { 12389209Swollman log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full"); 12399209Swollman ++mrtstat.mrts_upq_sockfull; 12409209Swollman m_free(mb_ntry); 12419209Swollman m_free(mb0); 12429209Swollman m_free(mb_rt); 12439209Swollman splx(s); 12449209Swollman return ENOBUFS; 12459209Swollman } 12469209Swollman 12472531Swollman rt = mtod(mb_rt, struct mfc *); 12482531Swollman 12492531Swollman /* insert new entry at head of hash chain */ 12502531Swollman rt->mfc_origin.s_addr = ip->ip_src.s_addr; 12512531Swollman rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr; 12529209Swollman rt->mfc_expire = UPCALL_EXPIRE; 12539209Swollman nexpire[hash]++; 12549209Swollman for (i = 0; i < numvifs; i++) 12559209Swollman rt->mfc_ttls[i] = 0; 12569209Swollman rt->mfc_parent = -1; 12572531Swollman 12582531Swollman /* link into table */ 12592531Swollman mb_rt->m_next = mfctable[hash]; 12602531Swollman mfctable[hash] = mb_rt; 12612531Swollman mb_rt->m_act = NULL; 12622531Swollman 12639209Swollman rte_m = mb_rt; 12649209Swollman } else { 12659209Swollman /* determine if q has overflowed */ 12669209Swollman for (rte_m = mb_rt, npkts = 0; rte_m->m_act; rte_m = rte_m->m_act) 12679209Swollman npkts++; 12682531Swollman 12699209Swollman if (npkts > MAX_UPQ) { 12709209Swollman mrtstat.mrts_upq_ovflw++; 12719209Swollman m_free(mb_ntry); 12729209Swollman m_free(mb0); 12739209Swollman splx(s); 12749209Swollman return 0; 12759209Swollman } 12762531Swollman } 12772531Swollman 12782531Swollman mb_ntry->m_act = NULL; 12792531Swollman rte = mtod(mb_ntry, struct rtdetq *); 12802531Swollman 12812531Swollman rte->m = mb0; 12822531Swollman rte->ifp = ifp; 12839209Swollman#ifdef UPCALL_TIMING 12849209Swollman rte->t = tp; 12859209Swollman#endif 12862531Swollman 12879209Swollman /* Add this entry to the end of the queue */ 12889209Swollman rte_m->m_act = mb_ntry; 12892531Swollman 12902531Swollman splx(s); 12912531Swollman 12922531Swollman return 0; 12939209Swollman } 12941541Srgrimes} 12951541Srgrimes 12962763Swollman#ifndef MROUTE_LKM 12972754Swollmanint (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, 12982763Swollman struct ip_moptions *) = X_ip_mforward; 12992763Swollman#endif 13002754Swollman 13011541Srgrimes/* 13022531Swollman * Clean up the cache entry if upcall is not serviced 13031541Srgrimes */ 13042531Swollmanstatic void 13059209Swollmanexpire_upcalls(void *unused) 13061541Srgrimes{ 13079209Swollman struct mbuf *mb_rt, *m, **nptr; 13082531Swollman struct rtdetq *rte; 13099209Swollman struct mfc *mfc; 13109209Swollman int i; 13112531Swollman int s; 13121541Srgrimes 13132531Swollman s = splnet(); 13149209Swollman for (i = 0; i < MFCTBLSIZ; i++) { 13159209Swollman if (nexpire[i] == 0) 13169209Swollman continue; 13179209Swollman nptr = &mfctable[i]; 13189209Swollman for (mb_rt = *nptr; mb_rt != NULL; mb_rt = *nptr) { 13199209Swollman mfc = mtod(mb_rt, struct mfc *); 13202531Swollman 13219209Swollman /* 13229209Swollman * Skip real cache entries 13239209Swollman * Make sure it wasn't marked to not expire (shouldn't happen) 13249209Swollman * If it expires now 13259209Swollman */ 13269209Swollman if (mb_rt->m_act != NULL && 13279209Swollman mfc->mfc_expire != 0 && 13289209Swollman --mfc->mfc_expire == 0) { 13299209Swollman if (mrtdebug & DEBUG_EXPIRE) 13309209Swollman log(LOG_DEBUG, "expire_upcalls: expiring (%x %x)", 13319209Swollman ntohl(mfc->mfc_origin.s_addr), 13329209Swollman ntohl(mfc->mfc_mcastgrp.s_addr)); 13339209Swollman /* 13349209Swollman * drop all the packets 13359209Swollman * free the mbuf with the pkt, if, timing info 13369209Swollman */ 13379209Swollman while (mb_rt->m_act) { 13389209Swollman m = mb_rt->m_act; 13399209Swollman mb_rt->m_act = m->m_act; 13409209Swollman 13419209Swollman rte = mtod(m, struct rtdetq *); 13429209Swollman m_freem(rte->m); 13439209Swollman m_free(m); 13449209Swollman } 13459209Swollman ++mrtstat.mrts_cache_cleanups; 13469209Swollman nexpire[i]--; 13472531Swollman 13489209Swollman MFREE(mb_rt, *nptr); 13499209Swollman } else { 13509209Swollman nptr = &mb_rt->m_next; 13519209Swollman } 13529209Swollman } 13532531Swollman } 13542531Swollman splx(s); 13559209Swollman timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); 13561541Srgrimes} 13571541Srgrimes 13581541Srgrimes/* 13592531Swollman * Packet forwarding routine once entry in the cache is made 13601541Srgrimes */ 13611541Srgrimesstatic int 13629209Swollmanip_mdq(m, ifp, rt, xmt_vif) 13632531Swollman register struct mbuf *m; 13642531Swollman register struct ifnet *ifp; 13652531Swollman register struct mfc *rt; 13669209Swollman register vifi_t xmt_vif; 13671541Srgrimes{ 13682531Swollman register struct ip *ip = mtod(m, struct ip *); 13692531Swollman register vifi_t vifi; 13702531Swollman register struct vif *vifp; 13719209Swollman register struct mbuf *tmp; 13729209Swollman register int plen = ntohs(ip->ip_len); 13731541Srgrimes 13749209Swollman/* 13759209Swollman * Macro to send packet on vif. Since RSVP packets don't get counted on 13769209Swollman * input, they shouldn't get counted on output, so statistics keeping is 13779209Swollman * seperate. 13789209Swollman */ 13799209Swollman#define MC_SEND(ip,vifp,m) { \ 13809209Swollman if ((vifp)->v_flags & VIFF_TUNNEL) \ 13819209Swollman encap_send((ip), (vifp), (m)); \ 13829209Swollman else \ 13839209Swollman phyint_send((ip), (vifp), (m)); \ 13849209Swollman} 13859209Swollman 13862531Swollman /* 13879209Swollman * If xmt_vif is not -1, send on only the requested vif. 13889209Swollman * 13899209Swollman * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.) 13909209Swollman */ 13919209Swollman if (xmt_vif < numvifs) { 13929209Swollman MC_SEND(ip, viftable + xmt_vif, m); 13939209Swollman return 1; 13949209Swollman } 13959209Swollman 13969209Swollman /* 13972531Swollman * Don't forward if it didn't arrive from the parent vif for its origin. 13982531Swollman */ 13992531Swollman vifi = rt->mfc_parent; 14009209Swollman if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) { 14012531Swollman /* came in the wrong interface */ 14029209Swollman if (mrtdebug & DEBUG_FORWARD) 14039209Swollman log(LOG_DEBUG, "wrong if: ifp %x vifi %d vififp %x", 14049209Swollman ifp, vifi, viftable[vifi].v_ifp); 14052531Swollman ++mrtstat.mrts_wrong_if; 14069209Swollman ++rt->mfc_wrong_if; 14079209Swollman /* 14089209Swollman * If we are doing PIM assert processing, and we are forwarding 14099209Swollman * packets on this interface, and it is a broadcast medium 14109209Swollman * interface (and not a tunnel), send a message to the routing daemon. 14119209Swollman */ 14129209Swollman if (pim_assert && rt->mfc_ttls[vifi] && 14139209Swollman (ifp->if_flags & IFF_BROADCAST) && 14149209Swollman !(viftable[vifi].v_flags & VIFF_TUNNEL)) { 14159209Swollman struct sockaddr_in k_igmpsrc; 14169209Swollman struct mbuf *mm; 14179209Swollman struct igmpmsg *im; 14189209Swollman int hlen = ip->ip_hl << 2; 14199209Swollman struct timeval now; 14209209Swollman register u_long delta; 14219209Swollman 14229209Swollman GET_TIME(now); 14239209Swollman 14249209Swollman TV_DELTA(rt->mfc_last_assert, now, delta); 14259209Swollman 14269209Swollman if (delta > ASSERT_MSG_TIME) { 14279209Swollman mm = m_copy(m, 0, hlen); 14289209Swollman if (mm && (M_HASCL(mm) || mm->m_len < hlen)) 14299209Swollman mm = m_pullup(mm, hlen); 14309209Swollman if (mm == NULL) { 14319209Swollman return ENOBUFS; 14329209Swollman } 14339209Swollman 14349209Swollman rt->mfc_last_assert = now; 14359209Swollman 14369209Swollman im = mtod(mm, struct igmpmsg *); 14379209Swollman im->im_msgtype = IGMPMSG_WRONGVIF; 14389209Swollman im->im_mbz = 0; 14399209Swollman im->im_vif = vifi; 14409209Swollman 14419209Swollman k_igmpsrc.sin_addr = im->im_src; 14429209Swollman 14439209Swollman socket_send(ip_mrouter, m, &k_igmpsrc); 14449209Swollman } 14459209Swollman } 14469209Swollman return 0; 14472531Swollman } 14481541Srgrimes 14499209Swollman /* If I sourced this packet, it counts as output, else it was input. */ 14509209Swollman if (ip->ip_src.s_addr == viftable[vifi].v_lcl_addr.s_addr) { 14519209Swollman viftable[vifi].v_pkt_out++; 14529209Swollman viftable[vifi].v_bytes_out += plen; 14539209Swollman } else { 14549209Swollman viftable[vifi].v_pkt_in++; 14559209Swollman viftable[vifi].v_bytes_in += plen; 14569209Swollman } 14572531Swollman rt->mfc_pkt_cnt++; 14589209Swollman rt->mfc_byte_cnt += plen; 14591541Srgrimes 14602531Swollman /* 14612531Swollman * For each vif, decide if a copy of the packet should be forwarded. 14622531Swollman * Forward if: 14632531Swollman * - the ttl exceeds the vif's threshold 14642531Swollman * - there are group members downstream on interface 14652531Swollman */ 14662531Swollman for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) 14672531Swollman if ((rt->mfc_ttls[vifi] > 0) && 14689209Swollman (ip->ip_ttl > rt->mfc_ttls[vifi])) { 14699209Swollman vifp->v_pkt_out++; 14709209Swollman vifp->v_bytes_out += plen; 14712531Swollman MC_SEND(ip, vifp, m); 14729209Swollman } 14732531Swollman 14742531Swollman return 0; 14751541Srgrimes} 14761541Srgrimes 14779209Swollman/* 14789209Swollman * check if a vif number is legal/ok. This is used by ip_output, to export 14799209Swollman * numvifs there, 14801541Srgrimes */ 14812531Swollmanint 14822763SwollmanX_legal_vif_num(vif) 14832531Swollman int vif; 14849209Swollman{ 14859209Swollman if (vif >= 0 && vif < numvifs) 14862531Swollman return(1); 14872531Swollman else 14882531Swollman return(0); 14892531Swollman} 14902531Swollman 14912763Swollman#ifndef MROUTE_LKM 14922763Swollmanint (*legal_vif_num)(int) = X_legal_vif_num; 14932763Swollman#endif 14942754Swollman 14959209Swollman/* 14969209Swollman * Return the local address used by this vif 14979209Swollman */ 14989209Swollmanu_long 14999209SwollmanX_ip_mcast_src(vifi) 15009209Swollman int vifi; 15019209Swollman{ 15029209Swollman if (vifi >= 0 && vifi < numvifs) 15039209Swollman return viftable[vifi].v_lcl_addr.s_addr; 15049209Swollman else 15059209Swollman return INADDR_ANY; 15069209Swollman} 15079209Swollman 15089209Swollman#ifndef MROUTE_LKM 15099209Swollmanu_long (*ip_mcast_src)(int) = X_ip_mcast_src; 15109209Swollman#endif 15119209Swollman 15122531Swollmanstatic void 15132531Swollmanphyint_send(ip, vifp, m) 15142531Swollman struct ip *ip; 15152531Swollman struct vif *vifp; 15162531Swollman struct mbuf *m; 15171541Srgrimes{ 15182531Swollman register struct mbuf *mb_copy; 15199209Swollman register int hlen = ip->ip_hl << 2; 15202531Swollman register struct ip_moptions *imo; 15211541Srgrimes 15223571Swollman /* 15239209Swollman * Make a new reference to the packet; make sure that 15249209Swollman * the IP header is actually copied, not just referenced, 15259209Swollman * so that ip_output() only scribbles on the copy. 15263571Swollman */ 15279209Swollman mb_copy = m_copy(m, 0, M_COPYALL); 15289209Swollman if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < hlen)) 15299209Swollman mb_copy = m_pullup(mb_copy, hlen); 15303571Swollman if (mb_copy == NULL) 15319209Swollman return; 15323571Swollman 15332531Swollman MALLOC(imo, struct ip_moptions *, sizeof *imo, M_IPMOPTS, M_NOWAIT); 15342531Swollman if (imo == NULL) { 15352531Swollman m_freem(mb_copy); 15362531Swollman return; 15372531Swollman } 15381541Srgrimes 15392531Swollman imo->imo_multicast_ifp = vifp->v_ifp; 15402531Swollman imo->imo_multicast_ttl = ip->ip_ttl - 1; 15412531Swollman imo->imo_multicast_loop = 1; 15429209Swollman imo->imo_multicast_vif = -1; 15431541Srgrimes 15442531Swollman if (vifp->v_rate_limit <= 0) 15452531Swollman tbf_send_packet(vifp, mb_copy, imo); 15462531Swollman else 15472531Swollman tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *), ip->ip_len, 15482531Swollman imo); 15492531Swollman} 15501541Srgrimes 15512531Swollmanstatic void 15522531Swollmanencap_send(ip, vifp, m) 15532531Swollman register struct ip *ip; 15542531Swollman register struct vif *vifp; 15552531Swollman register struct mbuf *m; 15561541Srgrimes{ 15572531Swollman register struct mbuf *mb_copy; 15582531Swollman register struct ip *ip_copy; 15593571Swollman int hlen = ip->ip_hl << 2; 15602531Swollman register int i, len = ip->ip_len; 15611541Srgrimes 15622531Swollman /* 15632531Swollman * copy the old packet & pullup it's IP header into the 15642531Swollman * new mbuf so we can modify it. Try to fill the new 15652531Swollman * mbuf since if we don't the ethernet driver will. 15662531Swollman */ 15672531Swollman MGET(mb_copy, M_DONTWAIT, MT_DATA); 15682531Swollman if (mb_copy == NULL) 15692531Swollman return; 15702531Swollman mb_copy->m_data += 16; 15712531Swollman mb_copy->m_len = sizeof(multicast_encap_iphdr); 15721541Srgrimes 15732531Swollman if ((mb_copy->m_next = m_copy(m, 0, M_COPYALL)) == NULL) { 15742531Swollman m_freem(mb_copy); 15752531Swollman return; 15762531Swollman } 15772531Swollman i = MHLEN - M_LEADINGSPACE(mb_copy); 15782531Swollman if (i > len) 15792531Swollman i = len; 15802531Swollman mb_copy = m_pullup(mb_copy, i); 15812531Swollman if (mb_copy == NULL) 15822531Swollman return; 15833571Swollman mb_copy->m_pkthdr.len = len + sizeof(multicast_encap_iphdr); 15841541Srgrimes 15852531Swollman /* 15862531Swollman * fill in the encapsulating IP header. 15872531Swollman */ 15882531Swollman ip_copy = mtod(mb_copy, struct ip *); 15892531Swollman *ip_copy = multicast_encap_iphdr; 15902531Swollman ip_copy->ip_id = htons(ip_id++); 15912531Swollman ip_copy->ip_len += len; 15922531Swollman ip_copy->ip_src = vifp->v_lcl_addr; 15932531Swollman ip_copy->ip_dst = vifp->v_rmt_addr; 15941541Srgrimes 15952531Swollman /* 15962531Swollman * turn the encapsulated IP header back into a valid one. 15972531Swollman */ 15982531Swollman ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr)); 15992531Swollman --ip->ip_ttl; 16002531Swollman HTONS(ip->ip_len); 16012531Swollman HTONS(ip->ip_off); 16022531Swollman ip->ip_sum = 0; 16032531Swollman#if defined(LBL) && !defined(ultrix) 16042531Swollman ip->ip_sum = ~oc_cksum((caddr_t)ip, ip->ip_hl << 2, 0); 16052531Swollman#else 16062531Swollman mb_copy->m_data += sizeof(multicast_encap_iphdr); 16072531Swollman ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2); 16082531Swollman mb_copy->m_data -= sizeof(multicast_encap_iphdr); 16092531Swollman#endif 16102531Swollman 16112531Swollman if (vifp->v_rate_limit <= 0) 16122531Swollman tbf_send_packet(vifp, mb_copy, 0); 16132531Swollman else 16142531Swollman tbf_control(vifp, mb_copy, ip, ip_copy->ip_len, 0); 16151541Srgrimes} 16161541Srgrimes 16171541Srgrimes/* 16182531Swollman * De-encapsulate a packet and feed it back through ip input (this 16192531Swollman * routine is called whenever IP gets a packet with proto type 16202531Swollman * ENCAP_PROTO and a local destination address). 16211541Srgrimes */ 16222531Swollmanvoid 16232763Swollman#ifdef MROUTE_LKM 16249209SwollmanX_ipip_input(m) 16252763Swollman#else 16269209Swollmanipip_input(m, iphlen) 16272763Swollman#endif 16289209Swollman register struct mbuf *m; 16299209Swollman int iphlen; 16302531Swollman{ 16312531Swollman struct ifnet *ifp = m->m_pkthdr.rcvif; 16322531Swollman register struct ip *ip = mtod(m, struct ip *); 16332531Swollman register int hlen = ip->ip_hl << 2; 16342531Swollman register int s; 16352531Swollman register struct ifqueue *ifq; 16362531Swollman register struct vif *vifp; 16371541Srgrimes 16389209Swollman if (!have_encap_tunnel) { 16399209Swollman rip_input(m); 16409209Swollman return; 16412531Swollman } 16422531Swollman /* 16432531Swollman * dump the packet if it's not to a multicast destination or if 16442531Swollman * we don't have an encapsulating tunnel with the source. 16452531Swollman * Note: This code assumes that the remote site IP address 16462531Swollman * uniquely identifies the tunnel (i.e., that this site has 16472531Swollman * at most one tunnel with the remote site). 16482531Swollman */ 16492531Swollman if (! IN_MULTICAST(ntohl(((struct ip *)((char *)ip + hlen))->ip_dst.s_addr))) { 16502531Swollman ++mrtstat.mrts_bad_tunnel; 16512531Swollman m_freem(m); 16522531Swollman return; 16532531Swollman } 16542531Swollman if (ip->ip_src.s_addr != last_encap_src) { 16552531Swollman register struct vif *vife; 16569209Swollman 16572531Swollman vifp = viftable; 16582531Swollman vife = vifp + numvifs; 16592531Swollman last_encap_src = ip->ip_src.s_addr; 16602531Swollman last_encap_vif = 0; 16612531Swollman for ( ; vifp < vife; ++vifp) 16622531Swollman if (vifp->v_rmt_addr.s_addr == ip->ip_src.s_addr) { 16632531Swollman if ((vifp->v_flags & (VIFF_TUNNEL|VIFF_SRCRT)) 16642531Swollman == VIFF_TUNNEL) 16652531Swollman last_encap_vif = vifp; 16662531Swollman break; 16672531Swollman } 16682531Swollman } 16692531Swollman if ((vifp = last_encap_vif) == 0) { 16702531Swollman last_encap_src = 0; 16712531Swollman mrtstat.mrts_cant_tunnel++; /*XXX*/ 16722531Swollman m_freem(m); 16732531Swollman if (mrtdebug) 16749209Swollman log(LOG_DEBUG, "ip_mforward: no tunnel with %x", 16752531Swollman ntohl(ip->ip_src.s_addr)); 16762531Swollman return; 16772531Swollman } 16782531Swollman ifp = vifp->v_ifp; 16797083Swollman 16807083Swollman if (hlen > IP_HDR_LEN) 16817083Swollman ip_stripoptions(m, (struct mbuf *) 0); 16827083Swollman m->m_data += IP_HDR_LEN; 16837083Swollman m->m_len -= IP_HDR_LEN; 16847083Swollman m->m_pkthdr.len -= IP_HDR_LEN; 16857083Swollman m->m_pkthdr.rcvif = ifp; 16867083Swollman 16872531Swollman ifq = &ipintrq; 16882531Swollman s = splimp(); 16892531Swollman if (IF_QFULL(ifq)) { 16902531Swollman IF_DROP(ifq); 16912531Swollman m_freem(m); 16922531Swollman } else { 16932531Swollman IF_ENQUEUE(ifq, m); 16942531Swollman /* 16952531Swollman * normally we would need a "schednetisr(NETISR_IP)" 16962531Swollman * here but we were called by ip_input and it is going 16972531Swollman * to loop back & try to dequeue the packet we just 16982531Swollman * queued as soon as we return so we avoid the 16992531Swollman * unnecessary software interrrupt. 17002531Swollman */ 17012531Swollman } 17022531Swollman splx(s); 17032531Swollman} 17041541Srgrimes 17052531Swollman/* 17062531Swollman * Token bucket filter module 17072531Swollman */ 17089209Swollmanstatic void 17092531Swollmantbf_control(vifp, m, ip, p_len, imo) 17102531Swollman register struct vif *vifp; 17111541Srgrimes register struct mbuf *m; 17122531Swollman register struct ip *ip; 17132531Swollman register u_long p_len; 17142531Swollman struct ip_moptions *imo; 17151541Srgrimes{ 17162531Swollman tbf_update_tokens(vifp); 17171541Srgrimes 17189209Swollman /* if there are enough tokens, 17192531Swollman * and the queue is empty, 17202531Swollman * send this packet out 17212531Swollman */ 17222531Swollman 17232531Swollman if (vifp->v_tbf->q_len == 0) { 17242531Swollman if (p_len <= vifp->v_tbf->n_tok) { 17252531Swollman vifp->v_tbf->n_tok -= p_len; 17262531Swollman tbf_send_packet(vifp, m, imo); 17272531Swollman } else if (p_len > MAX_BKT_SIZE) { 17282531Swollman /* drop if packet is too large */ 17292531Swollman mrtstat.mrts_pkt2large++; 17302531Swollman m_freem(m); 17312531Swollman return; 17321541Srgrimes } else { 17332531Swollman /* queue packet and timeout till later */ 17342531Swollman tbf_queue(vifp, m, ip, imo); 17352531Swollman timeout(tbf_reprocess_q, (caddr_t)vifp, 1); 17362531Swollman } 17372531Swollman } else if (vifp->v_tbf->q_len < MAXQSIZE) { 17382531Swollman /* finite queue length, so queue pkts and process queue */ 17392531Swollman tbf_queue(vifp, m, ip, imo); 17402531Swollman tbf_process_q(vifp); 17412531Swollman } else { 17422531Swollman /* queue length too much, try to dq and queue and process */ 17432531Swollman if (!tbf_dq_sel(vifp, ip)) { 17442531Swollman mrtstat.mrts_q_overflow++; 17452531Swollman m_freem(m); 17462531Swollman return; 17472531Swollman } else { 17482531Swollman tbf_queue(vifp, m, ip, imo); 17492531Swollman tbf_process_q(vifp); 17502531Swollman } 17512531Swollman } 17522531Swollman return; 17532531Swollman} 17541541Srgrimes 17559209Swollman/* 17562531Swollman * adds a packet to the queue at the interface 17572531Swollman */ 17589209Swollmanstatic void 17599209Swollmantbf_queue(vifp, m, ip, imo) 17602531Swollman register struct vif *vifp; 17612531Swollman register struct mbuf *m; 17622531Swollman register struct ip *ip; 17632531Swollman struct ip_moptions *imo; 17642531Swollman{ 17652531Swollman register u_long ql; 17662531Swollman register int index = (vifp - viftable); 17672531Swollman register int s = splnet(); 17681541Srgrimes 17692531Swollman ql = vifp->v_tbf->q_len; 17701541Srgrimes 17712531Swollman qtable[index][ql].pkt_m = m; 17722531Swollman qtable[index][ql].pkt_len = (mtod(m, struct ip *))->ip_len; 17732531Swollman qtable[index][ql].pkt_ip = ip; 17742531Swollman qtable[index][ql].pkt_imo = imo; 17751541Srgrimes 17762531Swollman vifp->v_tbf->q_len++; 17772531Swollman splx(s); 17782531Swollman} 17791541Srgrimes 17801541Srgrimes 17819209Swollman/* 17822531Swollman * processes the queue at the interface 17832531Swollman */ 17849209Swollmanstatic void 17852531Swollmantbf_process_q(vifp) 17862531Swollman register struct vif *vifp; 17872531Swollman{ 17882531Swollman register struct pkt_queue pkt_1; 17892531Swollman register int index = (vifp - viftable); 17902531Swollman register int s = splnet(); 17911541Srgrimes 17922531Swollman /* loop through the queue at the interface and send as many packets 17932531Swollman * as possible 17942531Swollman */ 17952531Swollman while (vifp->v_tbf->q_len > 0) { 17962531Swollman /* locate the first packet */ 17979209Swollman pkt_1.pkt_len = (qtable[index][0]).pkt_len; 17982531Swollman pkt_1.pkt_m = (qtable[index][0]).pkt_m; 17992531Swollman pkt_1.pkt_ip = (qtable[index][0]).pkt_ip; 18002531Swollman pkt_1.pkt_imo = (qtable[index][0]).pkt_imo; 18012531Swollman 18022531Swollman /* determine if the packet can be sent */ 18032531Swollman if (pkt_1.pkt_len <= vifp->v_tbf->n_tok) { 18042531Swollman /* if so, 18052531Swollman * reduce no of tokens, dequeue the queue, 18062531Swollman * send the packet. 18072531Swollman */ 18082531Swollman vifp->v_tbf->n_tok -= pkt_1.pkt_len; 18092531Swollman 18102531Swollman tbf_dequeue(vifp, 0); 18112531Swollman 18122531Swollman tbf_send_packet(vifp, pkt_1.pkt_m, pkt_1.pkt_imo); 18132531Swollman 18142531Swollman } else break; 18152531Swollman } 18162531Swollman splx(s); 18171541Srgrimes} 18181541Srgrimes 18199209Swollman/* 18202531Swollman * removes the jth packet from the queue at the interface 18212531Swollman */ 18229209Swollmanstatic void 18239209Swollmantbf_dequeue(vifp,j) 18242531Swollman register struct vif *vifp; 18252531Swollman register int j; 18261541Srgrimes{ 18272531Swollman register u_long index = vifp - viftable; 18282531Swollman register int i; 18291541Srgrimes 18302531Swollman for (i=j+1; i <= vifp->v_tbf->q_len - 1; i++) { 18312531Swollman qtable[index][i-1].pkt_m = qtable[index][i].pkt_m; 18322531Swollman qtable[index][i-1].pkt_len = qtable[index][i].pkt_len; 18332531Swollman qtable[index][i-1].pkt_ip = qtable[index][i].pkt_ip; 18342531Swollman qtable[index][i-1].pkt_imo = qtable[index][i].pkt_imo; 18359209Swollman } 18362531Swollman qtable[index][i-1].pkt_m = NULL; 18372531Swollman qtable[index][i-1].pkt_len = NULL; 18382531Swollman qtable[index][i-1].pkt_ip = NULL; 18392531Swollman qtable[index][i-1].pkt_imo = NULL; 18401541Srgrimes 18412531Swollman vifp->v_tbf->q_len--; 18421541Srgrimes 18432531Swollman if (tbfdebug > 1) 18449209Swollman log(LOG_DEBUG, "tbf_dequeue: vif# %d qlen %d",vifp-viftable, i-1); 18451541Srgrimes} 18461541Srgrimes 18479209Swollmanstatic void 18482531Swollmantbf_reprocess_q(xvifp) 18492531Swollman void *xvifp; 18501541Srgrimes{ 18512531Swollman register struct vif *vifp = xvifp; 18529209Swollman if (ip_mrouter == NULL) 18532531Swollman return; 18541541Srgrimes 18552531Swollman tbf_update_tokens(vifp); 18561541Srgrimes 18572531Swollman tbf_process_q(vifp); 18582531Swollman 18592531Swollman if (vifp->v_tbf->q_len) 18602531Swollman timeout(tbf_reprocess_q, (caddr_t)vifp, 1); 18612531Swollman} 18622531Swollman 18632531Swollman/* function that will selectively discard a member of the queue 18642531Swollman * based on the precedence value and the priority obtained through 18652531Swollman * a lookup table - not yet implemented accurately! 18662531Swollman */ 18679209Swollmanstatic int 18682531Swollmantbf_dq_sel(vifp, ip) 18692531Swollman register struct vif *vifp; 18702531Swollman register struct ip *ip; 18712531Swollman{ 18722531Swollman register int i; 18732531Swollman register int s = splnet(); 18742531Swollman register u_int p; 18752531Swollman 18762531Swollman p = priority(vifp, ip); 18772531Swollman 18782531Swollman for(i=vifp->v_tbf->q_len-1;i >= 0;i--) { 18792531Swollman if (p > priority(vifp, qtable[vifp-viftable][i].pkt_ip)) { 18802531Swollman m_freem(qtable[vifp-viftable][i].pkt_m); 18812531Swollman tbf_dequeue(vifp,i); 18822531Swollman splx(s); 18832531Swollman mrtstat.mrts_drop_sel++; 18842531Swollman return(1); 18851541Srgrimes } 18862531Swollman } 18872531Swollman splx(s); 18882531Swollman return(0); 18892531Swollman} 18901541Srgrimes 18919209Swollmanstatic void 18922531Swollmantbf_send_packet(vifp, m, imo) 18932531Swollman register struct vif *vifp; 18942531Swollman register struct mbuf *m; 18952531Swollman struct ip_moptions *imo; 18962531Swollman{ 18972531Swollman int error; 18982531Swollman int s = splnet(); 18991541Srgrimes 19009209Swollman if (vifp->v_flags & VIFF_TUNNEL) { 19012531Swollman /* If tunnel options */ 19022531Swollman ip_output(m, (struct mbuf *)0, (struct route *)0, 19032531Swollman IP_FORWARDING, imo); 19042531Swollman } else { 19052531Swollman /* if physical interface option, extract the options and then send */ 19062531Swollman error = ip_output(m, (struct mbuf *)0, (struct route *)0, 19072531Swollman IP_FORWARDING, imo); 19082531Swollman FREE(imo, M_IPMOPTS); 19092531Swollman 19109209Swollman if (mrtdebug & DEBUG_XMIT) 19119209Swollman log(LOG_DEBUG, "phyint_send on vif %d err %d", vifp-viftable, error); 19122531Swollman } 19132531Swollman splx(s); 19141541Srgrimes} 19152531Swollman 19162531Swollman/* determine the current time and then 19172531Swollman * the elapsed time (between the last time and time now) 19182531Swollman * in milliseconds & update the no. of tokens in the bucket 19192531Swollman */ 19209209Swollmanstatic void 19212531Swollmantbf_update_tokens(vifp) 19222531Swollman register struct vif *vifp; 19232531Swollman{ 19242531Swollman struct timeval tp; 19252531Swollman register u_long t; 19262531Swollman register u_long elapsed; 19272531Swollman register int s = splnet(); 19282531Swollman 19292531Swollman GET_TIME(tp); 19302531Swollman 19312531Swollman t = tp.tv_sec*1000 + tp.tv_usec/1000; 19322531Swollman 19332531Swollman elapsed = (t - vifp->v_tbf->last_pkt_t) * vifp->v_rate_limit /8; 19342531Swollman vifp->v_tbf->n_tok += elapsed; 19352531Swollman vifp->v_tbf->last_pkt_t = t; 19362531Swollman 19372531Swollman if (vifp->v_tbf->n_tok > MAX_BKT_SIZE) 19382531Swollman vifp->v_tbf->n_tok = MAX_BKT_SIZE; 19392531Swollman 19402531Swollman splx(s); 19412531Swollman} 19422531Swollman 19432531Swollmanstatic int 19442531Swollmanpriority(vifp, ip) 19452531Swollman register struct vif *vifp; 19462531Swollman register struct ip *ip; 19472531Swollman{ 19482531Swollman register int prio; 19492531Swollman 19509209Swollman /* temporary hack; may add general packet classifier some day */ 19512531Swollman 19529209Swollman /* 19539209Swollman * The UDP port space is divided up into four priority ranges: 19549209Swollman * [0, 16384) : unclassified - lowest priority 19559209Swollman * [16384, 32768) : audio - highest priority 19569209Swollman * [32768, 49152) : whiteboard - medium priority 19579209Swollman * [49152, 65536) : video - low priority 19589209Swollman */ 19599209Swollman if (ip->ip_p == IPPROTO_UDP) { 19609209Swollman struct udphdr *udp = (struct udphdr *)(((char *)ip) + (ip->ip_hl << 2)); 19619209Swollman switch (ntohs(udp->uh_dport) & 0xc000) { 19629209Swollman case 0x4000: 19639209Swollman prio = 70; 19649209Swollman break; 19659209Swollman case 0x8000: 19669209Swollman prio = 60; 19679209Swollman break; 19689209Swollman case 0xc000: 19699209Swollman prio = 55; 19709209Swollman break; 19719209Swollman default: 19729209Swollman prio = 50; 19739209Swollman break; 19749209Swollman } 19759209Swollman if (tbfdebug > 1) 19769209Swollman log(LOG_DEBUG, "port %x prio%d", ntohs(udp->uh_dport), prio); 19779209Swollman } else { 19789209Swollman prio = 50; 19799209Swollman } 19809209Swollman return prio; 19819209Swollman} 19828876Srgrimes 19839209Swollman/* 19849209Swollman * End of token bucket filter modifications 19859209Swollman */ 19862531Swollman 19879209Swollmanint 19889209Swollmanip_rsvp_vif_init(so, m) 19899209Swollman struct socket *so; 19909209Swollman struct mbuf *m; 19919209Swollman{ 19929209Swollman int i; 19939209Swollman register int s; 19949209Swollman 19959209Swollman if (rsvpdebug) 19969209Swollman printf("ip_rsvp_vif_init: so_type = %d, pr_protocol = %d\n", 19979209Swollman so->so_type, so->so_proto->pr_protocol); 19989209Swollman 19999209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 20009209Swollman return EOPNOTSUPP; 20019209Swollman 20029209Swollman /* Check mbuf. */ 20039209Swollman if (m == NULL || m->m_len != sizeof(int)) { 20049209Swollman return EINVAL; 20052531Swollman } 20069209Swollman i = *(mtod(m, int *)); 20079209Swollman 20089209Swollman if (rsvpdebug) 20099209Swollman printf("ip_rsvp_vif_init: vif = %d rsvp_on = %d\n",i,rsvp_on); 20109209Swollman 20119209Swollman s = splnet(); 20122531Swollman 20139209Swollman /* Check vif. */ 20149209Swollman if (!legal_vif_num(i)) { 20159209Swollman splx(s); 20169209Swollman return EADDRNOTAVAIL; 20179209Swollman } 20182531Swollman 20199209Swollman /* Check if socket is available. */ 20209209Swollman if (viftable[i].v_rsvpd != NULL) { 20219209Swollman splx(s); 20229209Swollman return EADDRINUSE; 20239209Swollman } 20249209Swollman 20259209Swollman viftable[i].v_rsvpd = so; 20269209Swollman /* This may seem silly, but we need to be sure we don't over-increment 20279209Swollman * the RSVP counter, in case something slips up. 20289209Swollman */ 20299209Swollman if (!viftable[i].v_rsvp_on) { 20309209Swollman viftable[i].v_rsvp_on = 1; 20319209Swollman rsvp_on++; 20329209Swollman } 20339209Swollman 20349209Swollman splx(s); 20359209Swollman return 0; 20362531Swollman} 20372531Swollman 20389209Swollmanint 20399209Swollmanip_rsvp_vif_done(so, m) 20409209Swollman struct socket *so; 20419209Swollman struct mbuf *m; 20429209Swollman{ 20439209Swollman int i; 20449209Swollman register int s; 20459209Swollman 20469209Swollman if (rsvpdebug) 20479209Swollman printf("ip_rsvp_vif_done: so_type = %d, pr_protocol = %d\n", 20489209Swollman so->so_type, so->so_proto->pr_protocol); 20499209Swollman 20509209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 20519209Swollman return EOPNOTSUPP; 20529209Swollman 20539209Swollman /* Check mbuf. */ 20549209Swollman if (m == NULL || m->m_len != sizeof(int)) { 20559209Swollman return EINVAL; 20569209Swollman } 20579209Swollman i = *(mtod(m, int *)); 20589209Swollman 20599209Swollman s = splnet(); 20609209Swollman 20619209Swollman /* Check vif. */ 20629209Swollman if (!legal_vif_num(i)) { 20639209Swollman splx(s); 20649209Swollman return EADDRNOTAVAIL; 20659209Swollman } 20662531Swollman 20679209Swollman if (rsvpdebug) 20689209Swollman printf("ip_rsvp_vif_done: v_rsvpd = %x so = %x\n", 20699209Swollman viftable[i].v_rsvpd, so); 20709209Swollman 20719209Swollman viftable[i].v_rsvpd = NULL; 20729209Swollman /* This may seem silly, but we need to be sure we don't over-decrement 20739209Swollman * the RSVP counter, in case something slips up. 20749209Swollman */ 20759209Swollman if (viftable[i].v_rsvp_on) { 20769209Swollman viftable[i].v_rsvp_on = 0; 20779209Swollman rsvp_on--; 20789209Swollman } 20799209Swollman 20809209Swollman splx(s); 20819209Swollman return 0; 20829209Swollman} 20839209Swollman 20849209Swollmanvoid 20859209Swollmanip_rsvp_force_done(so) 20869209Swollman struct socket *so; 20879209Swollman{ 20889209Swollman int vifi; 20899209Swollman register int s; 20909209Swollman 20919209Swollman /* Don't bother if it is not the right type of socket. */ 20929209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 20939209Swollman return; 20949209Swollman 20959209Swollman s = splnet(); 20969209Swollman 20979209Swollman /* The socket may be attached to more than one vif...this 20989209Swollman * is perfectly legal. 20999209Swollman */ 21009209Swollman for (vifi = 0; vifi < numvifs; vifi++) { 21019209Swollman if (viftable[vifi].v_rsvpd == so) { 21029209Swollman viftable[vifi].v_rsvpd = NULL; 21039209Swollman /* This may seem silly, but we need to be sure we don't 21049209Swollman * over-decrement the RSVP counter, in case something slips up. 21059209Swollman */ 21069209Swollman if (viftable[vifi].v_rsvp_on) { 21079209Swollman viftable[vifi].v_rsvp_on = 0; 21089209Swollman rsvp_on--; 21099209Swollman } 21109209Swollman } 21119209Swollman } 21129209Swollman 21139209Swollman splx(s); 21149209Swollman return; 21159209Swollman} 21169209Swollman 21179209Swollmanvoid 21189209Swollmanrsvp_input(m, ifp) 21199209Swollman struct mbuf *m; 21209209Swollman struct ifnet *ifp; 21219209Swollman{ 21229209Swollman int vifi; 21239209Swollman register struct ip *ip = mtod(m, struct ip *); 21249209Swollman static struct sockaddr_in rsvp_src = { AF_INET }; 21259209Swollman register int s; 21269209Swollman 21279209Swollman if (rsvpdebug) 21289209Swollman printf("rsvp_input: rsvp_on %d\n",rsvp_on); 21299209Swollman 21309209Swollman /* Can still get packets with rsvp_on = 0 if there is a local member 21319209Swollman * of the group to which the RSVP packet is addressed. But in this 21329209Swollman * case we want to throw the packet away. 21339209Swollman */ 21349209Swollman if (!rsvp_on) { 21359209Swollman m_freem(m); 21369209Swollman return; 21379209Swollman } 21389209Swollman 21399209Swollman /* If the old-style non-vif-associated socket is set, then use 21409209Swollman * it and ignore the new ones. 21419209Swollman */ 21429209Swollman if (ip_rsvpd != NULL) { 21439209Swollman if (rsvpdebug) 21449209Swollman printf("rsvp_input: Sending packet up old-style socket\n"); 21459209Swollman rip_input(m); 21469209Swollman return; 21479209Swollman } 21489209Swollman 21499209Swollman s = splnet(); 21509209Swollman 21519209Swollman if (rsvpdebug) 21529209Swollman printf("rsvp_input: check vifs\n"); 21539209Swollman 21549209Swollman /* Find which vif the packet arrived on. */ 21559209Swollman for (vifi = 0; vifi < numvifs; vifi++) { 21569209Swollman if (viftable[vifi].v_ifp == ifp) 21579209Swollman break; 21589209Swollman } 21599209Swollman 21609209Swollman if (vifi == numvifs) { 21619209Swollman /* Can't find vif packet arrived on. Drop packet. */ 21629209Swollman if (rsvpdebug) 21639209Swollman printf("rsvp_input: Can't find vif for packet...dropping it.\n"); 21649209Swollman m_freem(m); 21659209Swollman splx(s); 21669209Swollman return; 21679209Swollman } 21689209Swollman 21699209Swollman if (rsvpdebug) 21709209Swollman printf("rsvp_input: check socket\n"); 21719209Swollman 21729209Swollman if (viftable[vifi].v_rsvpd == NULL) { 21739209Swollman /* drop packet, since there is no specific socket for this 21749209Swollman * interface */ 21759209Swollman if (rsvpdebug) 21769209Swollman printf("rsvp_input: No socket defined for vif %d\n",vifi); 21779209Swollman m_freem(m); 21789209Swollman splx(s); 21799209Swollman return; 21809209Swollman } 21819209Swollman rsvp_src.sin_addr = ip->ip_src; 21829209Swollman 21839209Swollman if (rsvpdebug && m) 21849209Swollman printf("rsvp_input: m->m_len = %d, sbspace() = %d\n", 21859209Swollman m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv))); 21869209Swollman 21879209Swollman if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) 21889209Swollman if (rsvpdebug) 21899209Swollman printf("rsvp_input: Failed to append to socket\n"); 21909209Swollman else 21919209Swollman if (rsvpdebug) 21929209Swollman printf("rsvp_input: send packet up\n"); 21939209Swollman 21949209Swollman splx(s); 21959209Swollman} 21969209Swollman 21972763Swollman#ifdef MROUTE_LKM 21982763Swollman#include <sys/conf.h> 21992763Swollman#include <sys/exec.h> 22002763Swollman#include <sys/sysent.h> 22012763Swollman#include <sys/lkm.h> 22022531Swollman 22032763SwollmanMOD_MISC("ip_mroute_mod") 22042763Swollman 22052763Swollmanstatic int 22062763Swollmanip_mroute_mod_handle(struct lkm_table *lkmtp, int cmd) 22072763Swollman{ 22082763Swollman int i; 22092763Swollman struct lkm_misc *args = lkmtp->private.lkm_misc; 22102763Swollman int err = 0; 22112763Swollman 22122763Swollman switch(cmd) { 22132763Swollman static int (*old_ip_mrouter_cmd)(); 22142763Swollman static int (*old_ip_mrouter_done)(); 22152763Swollman static int (*old_ip_mforward)(); 22162763Swollman static int (*old_mrt_ioctl)(); 22176616Sbde static void (*old_proto4_input)(); 22182763Swollman static int (*old_legal_vif_num)(); 22192763Swollman extern struct protosw inetsw[]; 22202763Swollman 22212763Swollman case LKM_E_LOAD: 22222763Swollman if(lkmexists(lkmtp) || ip_mrtproto) 22232763Swollman return(EEXIST); 22242763Swollman old_ip_mrouter_cmd = ip_mrouter_cmd; 22252763Swollman ip_mrouter_cmd = X_ip_mrouter_cmd; 22262763Swollman old_ip_mrouter_done = ip_mrouter_done; 22272763Swollman ip_mrouter_done = X_ip_mrouter_done; 22282763Swollman old_ip_mforward = ip_mforward; 22292763Swollman ip_mforward = X_ip_mforward; 22302763Swollman old_mrt_ioctl = mrt_ioctl; 22312763Swollman mrt_ioctl = X_mrt_ioctl; 22327083Swollman old_proto4_input = inetsw[ip_protox[ENCAP_PROTO]].pr_input; 22339209Swollman inetsw[ip_protox[ENCAP_PROTO]].pr_input = X_ipip_input; 22342763Swollman old_legal_vif_num = legal_vif_num; 22352763Swollman legal_vif_num = X_legal_vif_num; 22362763Swollman ip_mrtproto = IGMP_DVMRP; 22372763Swollman 22382763Swollman printf("\nIP multicast routing loaded\n"); 22392763Swollman break; 22402763Swollman 22412763Swollman case LKM_E_UNLOAD: 22422763Swollman if (ip_mrouter) 22432763Swollman return EINVAL; 22442763Swollman 22452763Swollman ip_mrouter_cmd = old_ip_mrouter_cmd; 22462763Swollman ip_mrouter_done = old_ip_mrouter_done; 22472763Swollman ip_mforward = old_ip_mforward; 22482763Swollman mrt_ioctl = old_mrt_ioctl; 22497083Swollman inetsw[ip_protox[ENCAP_PROTO]].pr_input = old_proto4_input; 22502763Swollman legal_vif_num = old_legal_vif_num; 22512763Swollman ip_mrtproto = 0; 22522763Swollman break; 22532763Swollman 22542763Swollman default: 22552763Swollman err = EINVAL; 22562763Swollman break; 22572763Swollman } 22582763Swollman 22592763Swollman return(err); 22602763Swollman} 22612763Swollman 22622763Swollmanint 22632763Swollmanip_mroute_mod(struct lkm_table *lkmtp, int cmd, int ver) { 22642763Swollman DISPATCH(lkmtp, cmd, ver, ip_mroute_mod_handle, ip_mroute_mod_handle, 22652763Swollman nosys); 22662763Swollman} 22672763Swollman 22682763Swollman#endif /* MROUTE_LKM */ 22692763Swollman#endif /* MROUTING */ 2270