ip_mroute.c revision 14549
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 1214549Sfenner * $Id: ip_mroute.c,v 1.29 1996/03/11 15:13:17 davidg Exp $ 131541Srgrimes */ 141541Srgrimes 1514328Speter#include "opt_mrouting.h" 161541Srgrimes 171541Srgrimes#include <sys/param.h> 1814546Sdg#include <sys/queue.h> 191549Srgrimes#include <sys/systm.h> 201541Srgrimes#include <sys/mbuf.h> 211541Srgrimes#include <sys/socket.h> 221541Srgrimes#include <sys/socketvar.h> 232531Swollman#include <sys/protosw.h> 242531Swollman#include <sys/errno.h> 251541Srgrimes#include <sys/time.h> 269209Swollman#include <sys/kernel.h> 272531Swollman#include <sys/ioctl.h> 282531Swollman#include <sys/syslog.h> 291541Srgrimes#include <net/if.h> 301541Srgrimes#include <net/route.h> 311541Srgrimes#include <netinet/in.h> 321541Srgrimes#include <netinet/in_systm.h> 331541Srgrimes#include <netinet/ip.h> 342531Swollman#include <netinet/ip_var.h> 351541Srgrimes#include <netinet/in_pcb.h> 361541Srgrimes#include <netinet/in_var.h> 371541Srgrimes#include <netinet/igmp.h> 381541Srgrimes#include <netinet/igmp_var.h> 391541Srgrimes#include <netinet/ip_mroute.h> 409209Swollman#include <netinet/udp.h> 411541Srgrimes 4212579Sbdeextern void rsvp_input __P((struct mbuf *m, int iphlen)); 4312579Sbde 442531Swollman#ifndef NTOHL 452531Swollman#if BYTE_ORDER != BIG_ENDIAN 462531Swollman#define NTOHL(d) ((d) = ntohl((d))) 472531Swollman#define NTOHS(d) ((d) = ntohs((u_short)(d))) 482531Swollman#define HTONL(d) ((d) = htonl((d))) 492531Swollman#define HTONS(d) ((d) = htons((u_short)(d))) 502531Swollman#else 512531Swollman#define NTOHL(d) 522531Swollman#define NTOHS(d) 532531Swollman#define HTONL(d) 542531Swollman#define HTONS(d) 552531Swollman#endif 562531Swollman#endif 571541Srgrimes 582531Swollman#ifndef MROUTING 5912579Sbdeextern void ipip_input __P((struct mbuf *m)); 6012579Sbdeextern u_long _ip_mcast_src __P((int vifi)); 6112579Sbdeextern int _ip_mforward __P((struct ip *ip, struct ifnet *ifp, 6212579Sbde struct mbuf *m, struct ip_moptions *imo)); 6312579Sbdeextern int _ip_mrouter_done __P((void)); 6412579Sbdeextern int _ip_mrouter_get __P((int cmd, struct socket *so, 6512579Sbde struct mbuf **m)); 6612579Sbdeextern int _ip_mrouter_set __P((int cmd, struct socket *so, 6712579Sbde struct mbuf *m)); 6812579Sbdeextern int _mrt_ioctl __P((int req, caddr_t data, struct proc *p)); 6912579Sbde 702531Swollman/* 712531Swollman * Dummy routines and globals used when multicast routing is not compiled in. 722531Swollman */ 731541Srgrimes 749209Swollmanstruct socket *ip_mrouter = NULL; 7512296Sphkstatic u_int ip_mrtproto = 0; 7612820Sphkstatic struct mrtstat mrtstat; 779209Swollmanu_int rsvpdebug = 0; 782531Swollman 792531Swollmanint 809209Swollman_ip_mrouter_set(cmd, so, m) 812531Swollman int cmd; 822531Swollman struct socket *so; 832531Swollman struct mbuf *m; 842531Swollman{ 852531Swollman return(EOPNOTSUPP); 862531Swollman} 872531Swollman 889209Swollmanint (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = _ip_mrouter_set; 892754Swollman 909209Swollman 912531Swollmanint 929209Swollman_ip_mrouter_get(cmd, so, m) 939209Swollman int cmd; 949209Swollman struct socket *so; 959209Swollman struct mbuf **m; 969209Swollman{ 979209Swollman return(EOPNOTSUPP); 989209Swollman} 999209Swollman 1009209Swollmanint (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = _ip_mrouter_get; 1019209Swollman 1029209Swollmanint 1032754Swollman_ip_mrouter_done() 1042531Swollman{ 1052531Swollman return(0); 1062531Swollman} 1072531Swollman 1082754Swollmanint (*ip_mrouter_done)(void) = _ip_mrouter_done; 1092754Swollman 1102531Swollmanint 1112754Swollman_ip_mforward(ip, ifp, m, imo) 1122531Swollman struct ip *ip; 1132531Swollman struct ifnet *ifp; 1142531Swollman struct mbuf *m; 1152754Swollman struct ip_moptions *imo; 1162531Swollman{ 1172531Swollman return(0); 1182531Swollman} 1192754Swollman 1202754Swollmanint (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, 1212754Swollman struct ip_moptions *) = _ip_mforward; 1222754Swollman 1232754Swollmanint 1242754Swollman_mrt_ioctl(int req, caddr_t data, struct proc *p) 1252754Swollman{ 1262754Swollman return EOPNOTSUPP; 1272754Swollman} 1282754Swollman 1292754Swollmanint (*mrt_ioctl)(int, caddr_t, struct proc *) = _mrt_ioctl; 1302754Swollman 1319209Swollmanvoid 1329209Swollmanrsvp_input(m, iphlen) /* XXX must fixup manually */ 1339209Swollman struct mbuf *m; 1349209Swollman int iphlen; 1359209Swollman{ 1369209Swollman /* Can still get packets with rsvp_on = 0 if there is a local member 1379209Swollman * of the group to which the RSVP packet is addressed. But in this 1389209Swollman * case we want to throw the packet away. 1399209Swollman */ 1409209Swollman if (!rsvp_on) { 1419209Swollman m_freem(m); 1429209Swollman return; 1439209Swollman } 1449209Swollman 1459209Swollman if (ip_rsvpd != NULL) { 1469209Swollman if (rsvpdebug) 1479209Swollman printf("rsvp_input: Sending packet up old-style socket\n"); 1482754Swollman rip_input(m); 1499209Swollman return; 1509209Swollman } 1519209Swollman /* Drop the packet */ 1529209Swollman m_freem(m); 1532754Swollman} 1542754Swollman 1559209Swollmanvoid ipip_input(struct mbuf *m) { /* XXX must fixup manually */ 1569209Swollman rip_input(m); 1579209Swollman} 1589209Swollman 1592754Swollmanint (*legal_vif_num)(int) = 0; 1602754Swollman 1619209Swollman/* 1629209Swollman * This should never be called, since IP_MULTICAST_VIF should fail, but 1639209Swollman * just in case it does get called, the code a little lower in ip_output 1649209Swollman * will assign the packet a local address. 1659209Swollman */ 1669209Swollmanu_long 1679209Swollman_ip_mcast_src(int vifi) { return INADDR_ANY; } 1689209Swollmanu_long (*ip_mcast_src)(int) = _ip_mcast_src; 1699209Swollman 1709209Swollmanint 1719209Swollmanip_rsvp_vif_init(so, m) 1729209Swollman struct socket *so; 1739209Swollman struct mbuf *m; 1749209Swollman{ 1759209Swollman return(EINVAL); 1769209Swollman} 1779209Swollman 1789209Swollmanint 1799209Swollmanip_rsvp_vif_done(so, m) 1809209Swollman struct socket *so; 1819209Swollman struct mbuf *m; 1829209Swollman{ 1839209Swollman return(EINVAL); 1849209Swollman} 1859209Swollman 1869209Swollmanvoid 1879209Swollmanip_rsvp_force_done(so) 1889209Swollman struct socket *so; 1899209Swollman{ 1909209Swollman return; 1919209Swollman} 1929209Swollman 1937083Swollman#else /* MROUTING */ 1942531Swollman 1959209Swollman#define M_HASCL(m) ((m)->m_flags & M_EXT) 1969209Swollman 1972531Swollman#define INSIZ sizeof(struct in_addr) 1982531Swollman#define same(a1, a2) \ 1992531Swollman (bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0) 2002531Swollman 2012531Swollman#define MT_MRTABLE MT_RTABLE /* since nothing else uses it */ 2022531Swollman 2031541Srgrimes/* 2041541Srgrimes * Globals. All but ip_mrouter and ip_mrtproto could be static, 2051541Srgrimes * except for netstat or debugging purposes. 2061541Srgrimes */ 2072763Swollman#ifndef MROUTE_LKM 20812579Sbdeextern void ipip_input __P((struct mbuf *m, int iphlen)); 2092531Swollmanstruct socket *ip_mrouter = NULL; 2102763Swollmanstruct mrtstat mrtstat; 2112763Swollman 2122531Swollmanint ip_mrtproto = IGMP_DVMRP; /* for netstat only */ 2137083Swollman#else /* MROUTE_LKM */ 21412579Sbde#error /* the function definition will have a syntax error */ 21512579Sbdeextern void X_ipip_input __P((struct mbuf *m)); 2162763Swollmanextern struct mrtstat mrtstat; 21712296Sphkstatic int ip_mrtproto; 2182763Swollman#endif 2191541Srgrimes 2202531Swollman#define NO_RTE_FOUND 0x1 2212531Swollman#define RTE_FOUND 0x2 2221541Srgrimes 22312820Sphkstatic struct mbuf *mfctable[MFCTBLSIZ]; 22412820Sphkstatic u_char nexpire[MFCTBLSIZ]; 22512820Sphkstatic struct vif viftable[MAXVIFS]; 22612296Sphkstatic u_int mrtdebug = 0; /* debug level */ 2279209Swollman#define DEBUG_MFC 0x02 2289209Swollman#define DEBUG_FORWARD 0x04 2299209Swollman#define DEBUG_EXPIRE 0x08 2309209Swollman#define DEBUG_XMIT 0x10 23112296Sphkstatic u_int tbfdebug = 0; /* tbf debug level */ 23212296Sphkstatic u_int rsvpdebug = 0; /* rsvp debug level */ 2332531Swollman 2349209Swollman#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */ 2359209Swollman#define UPCALL_EXPIRE 6 /* number of timeouts */ 2362531Swollman 2371541Srgrimes/* 2382531Swollman * Define the token bucket filter structures 2399209Swollman * tbftable -> each vif has one of these for storing info 2402531Swollman */ 2412531Swollman 24212820Sphkstatic struct tbf tbftable[MAXVIFS]; 24310203Swollman#define TBF_REPROCESS (hz / 100) /* 100x / second */ 2442531Swollman 2452531Swollman/* 2462531Swollman * 'Interfaces' associated with decapsulator (so we can tell 2472531Swollman * packets that went through it from ones that get reflected 2482531Swollman * by a broken gateway). These interfaces are never linked into 2492531Swollman * the system ifnet list & no routes point to them. I.e., packets 2502531Swollman * can't be sent this way. They only exist as a placeholder for 2512531Swollman * multicast source verification. 2522531Swollman */ 25312820Sphkstatic struct ifnet multicast_decap_if[MAXVIFS]; 2542531Swollman 2552531Swollman#define ENCAP_TTL 64 2569209Swollman#define ENCAP_PROTO IPPROTO_IPIP /* 4 */ 2572531Swollman 2582531Swollman/* prototype IP hdr for encapsulated packets */ 25912296Sphkstatic struct ip multicast_encap_iphdr = { 2602754Swollman#if BYTE_ORDER == LITTLE_ENDIAN 2612531Swollman sizeof(struct ip) >> 2, IPVERSION, 2622531Swollman#else 2632531Swollman IPVERSION, sizeof(struct ip) >> 2, 2642531Swollman#endif 2652531Swollman 0, /* tos */ 2662531Swollman sizeof(struct ip), /* total length */ 2672531Swollman 0, /* id */ 2682531Swollman 0, /* frag offset */ 2699209Swollman ENCAP_TTL, ENCAP_PROTO, 2702531Swollman 0, /* checksum */ 2712531Swollman}; 2722531Swollman 2732531Swollman/* 2741541Srgrimes * Private variables. 2751541Srgrimes */ 2762531Swollmanstatic vifi_t numvifs = 0; 2779209Swollmanstatic int have_encap_tunnel = 0; 2781541Srgrimes 2791541Srgrimes/* 2809209Swollman * one-back cache used by ipip_input to locate a tunnel's vif 2812531Swollman * given a datagram's src ip address. 2822531Swollman */ 2832531Swollmanstatic u_long last_encap_src; 2842531Swollmanstatic struct vif *last_encap_vif; 2852531Swollman 28612579Sbdestatic u_long X_ip_mcast_src __P((int vifi)); 28712579Sbdestatic int X_ip_mforward __P((struct ip *ip, struct ifnet *ifp, struct mbuf *m, struct ip_moptions *imo)); 28812579Sbdestatic int X_ip_mrouter_done __P((void)); 28912579Sbdestatic int X_ip_mrouter_get __P((int cmd, struct socket *so, struct mbuf **m)); 29012579Sbdestatic int X_ip_mrouter_set __P((int cmd, struct socket *so, struct mbuf *m)); 29112579Sbdestatic int X_legal_vif_num __P((int vif)); 29212579Sbdestatic int X_mrt_ioctl __P((int cmd, caddr_t data)); 29312579Sbde 2949209Swollmanstatic int get_sg_cnt(struct sioc_sg_req *); 2959209Swollmanstatic int get_vif_cnt(struct sioc_vif_req *); 29612296Sphkstatic int ip_mrouter_init(struct socket *, struct mbuf *); 2972531Swollmanstatic int add_vif(struct vifctl *); 2982531Swollmanstatic int del_vif(vifi_t *); 2992531Swollmanstatic int add_mfc(struct mfcctl *); 3009209Swollmanstatic int del_mfc(struct mfcctl *); 30112579Sbdestatic int socket_send(struct socket *, struct mbuf *, struct sockaddr_in *); 3029209Swollmanstatic int get_version(struct mbuf *); 3039209Swollmanstatic int get_assert(struct mbuf *); 3049209Swollmanstatic int set_assert(int *); 3059209Swollmanstatic void expire_upcalls(void *); 3069209Swollmanstatic int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *, 3079209Swollman vifi_t); 3082531Swollmanstatic void phyint_send(struct ip *, struct vif *, struct mbuf *); 3092531Swollmanstatic void encap_send(struct ip *, struct vif *, struct mbuf *); 31010203Swollmanstatic void tbf_control(struct vif *, struct mbuf *, struct ip *, u_long); 31110203Swollmanstatic void tbf_queue(struct vif *, struct mbuf *); 3129209Swollmanstatic void tbf_process_q(struct vif *); 3139209Swollmanstatic void tbf_reprocess_q(void *); 3149209Swollmanstatic int tbf_dq_sel(struct vif *, struct ip *); 31510203Swollmanstatic void tbf_send_packet(struct vif *, struct mbuf *); 3169209Swollmanstatic void tbf_update_tokens(struct vif *); 3172531Swollmanstatic int priority(struct vif *, struct ip *); 3189209Swollmanvoid multiencap_decap(struct mbuf *); 3192531Swollman 3202531Swollman/* 3219209Swollman * whether or not special PIM assert processing is enabled. 3228876Srgrimes */ 3239209Swollmanstatic int pim_assert; 3249209Swollman/* 3259209Swollman * Rate limit for assert notification messages, in usec 3269209Swollman */ 3279209Swollman#define ASSERT_MSG_TIME 3000000 3282531Swollman 3292531Swollman/* 3309209Swollman * Hash function for a source, group entry 3312531Swollman */ 3329209Swollman#define MFCHASH(a, g) MFCHASHMOD(((a) >> 20) ^ ((a) >> 10) ^ (a) ^ \ 3339209Swollman ((g) >> 20) ^ ((g) >> 10) ^ (g)) 3342531Swollman 3352531Swollman/* 3362531Swollman * Find a route for a given origin IP address and Multicast group address 3372531Swollman * Type of service parameter to be added in the future!!! 3382531Swollman */ 3399209Swollman 3402531Swollman#define MFCFIND(o, g, rt) { \ 3419209Swollman register struct mbuf *_mb_rt = mfctable[MFCHASH(o,g)]; \ 3429209Swollman register struct mfc *_rt = NULL; \ 3439209Swollman rt = NULL; \ 3442531Swollman ++mrtstat.mrts_mfc_lookups; \ 3459209Swollman while (_mb_rt) { \ 3469209Swollman _rt = mtod(_mb_rt, struct mfc *); \ 3479209Swollman if ((_rt->mfc_origin.s_addr == o) && \ 3489209Swollman (_rt->mfc_mcastgrp.s_addr == g) && \ 3499209Swollman (_mb_rt->m_act == NULL)) { \ 3509209Swollman rt = _rt; \ 3519209Swollman break; \ 3529209Swollman } \ 3539209Swollman _mb_rt = _mb_rt->m_next; \ 3549209Swollman } \ 3559209Swollman if (rt == NULL) { \ 3569209Swollman ++mrtstat.mrts_mfc_misses; \ 3579209Swollman } \ 3582531Swollman} 3592531Swollman 3602531Swollman 3612531Swollman/* 3622531Swollman * Macros to compute elapsed time efficiently 3632531Swollman * Borrowed from Van Jacobson's scheduling code 3642531Swollman */ 3652531Swollman#define TV_DELTA(a, b, delta) { \ 3662531Swollman register int xxs; \ 3672531Swollman \ 3682531Swollman delta = (a).tv_usec - (b).tv_usec; \ 3692531Swollman if ((xxs = (a).tv_sec - (b).tv_sec)) { \ 3702531Swollman switch (xxs) { \ 3712531Swollman case 2: \ 3722531Swollman delta += 1000000; \ 3732531Swollman /* fall through */ \ 3742531Swollman case 1: \ 3752531Swollman delta += 1000000; \ 3762531Swollman break; \ 3772531Swollman default: \ 3782531Swollman delta += (1000000 * xxs); \ 3792531Swollman } \ 3802531Swollman } \ 3812531Swollman} 3822531Swollman 3832531Swollman#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \ 3842531Swollman (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) 3852531Swollman 3869209Swollman#ifdef UPCALL_TIMING 3879209Swollmanu_long upcall_data[51]; 3889209Swollmanstatic void collate(struct timeval *); 3899209Swollman#endif /* UPCALL_TIMING */ 3909209Swollman 3919209Swollman 3922531Swollman/* 3939209Swollman * Handle MRT setsockopt commands to modify the multicast routing tables. 3941541Srgrimes */ 39512296Sphkstatic int 3969209SwollmanX_ip_mrouter_set(cmd, so, m) 3972531Swollman int cmd; 3982531Swollman struct socket *so; 3992531Swollman struct mbuf *m; 4001541Srgrimes{ 4019209Swollman if (cmd != MRT_INIT && so != ip_mrouter) return EACCES; 4021541Srgrimes 4032531Swollman switch (cmd) { 4049209Swollman case MRT_INIT: return ip_mrouter_init(so, m); 4059209Swollman case MRT_DONE: return ip_mrouter_done(); 4069209Swollman case MRT_ADD_VIF: return add_vif (mtod(m, struct vifctl *)); 4079209Swollman case MRT_DEL_VIF: return del_vif (mtod(m, vifi_t *)); 4089209Swollman case MRT_ADD_MFC: return add_mfc (mtod(m, struct mfcctl *)); 4099209Swollman case MRT_DEL_MFC: return del_mfc (mtod(m, struct mfcctl *)); 4109209Swollman case MRT_ASSERT: return set_assert(mtod(m, int *)); 4112531Swollman default: return EOPNOTSUPP; 4122531Swollman } 4132531Swollman} 4141541Srgrimes 4152763Swollman#ifndef MROUTE_LKM 4169209Swollmanint (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = X_ip_mrouter_set; 4172763Swollman#endif 4181541Srgrimes 4192531Swollman/* 4209209Swollman * Handle MRT getsockopt commands 4219209Swollman */ 42212296Sphkstatic int 4239209SwollmanX_ip_mrouter_get(cmd, so, m) 4249209Swollman int cmd; 4259209Swollman struct socket *so; 4269209Swollman struct mbuf **m; 4279209Swollman{ 4289209Swollman struct mbuf *mb; 4299209Swollman 4309209Swollman if (so != ip_mrouter) return EACCES; 4319209Swollman 4329209Swollman *m = mb = m_get(M_WAIT, MT_SOOPTS); 4339209Swollman 4349209Swollman switch (cmd) { 4359209Swollman case MRT_VERSION: return get_version(mb); 4369209Swollman case MRT_ASSERT: return get_assert(mb); 4379209Swollman default: return EOPNOTSUPP; 4389209Swollman } 4399209Swollman} 4409209Swollman 4419209Swollman#ifndef MROUTE_LKM 4429209Swollmanint (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = X_ip_mrouter_get; 4439209Swollman#endif 4449209Swollman 4459209Swollman/* 4462531Swollman * Handle ioctl commands to obtain information from the cache 4472531Swollman */ 44812296Sphkstatic int 4492763SwollmanX_mrt_ioctl(cmd, data) 4502531Swollman int cmd; 4512531Swollman caddr_t data; 4522531Swollman{ 4532531Swollman int error = 0; 4541541Srgrimes 4552531Swollman switch (cmd) { 4569209Swollman case (SIOCGETVIFCNT): 4579209Swollman return (get_vif_cnt((struct sioc_vif_req *)data)); 4589209Swollman break; 4599209Swollman case (SIOCGETSGCNT): 4609209Swollman return (get_sg_cnt((struct sioc_sg_req *)data)); 4619209Swollman break; 4622531Swollman default: 4639209Swollman return (EINVAL); 4649209Swollman break; 4652531Swollman } 4662531Swollman return error; 4672531Swollman} 4681541Srgrimes 4692763Swollman#ifndef MROUTE_LKM 47012579Sbdeint (*mrt_ioctl)(int, caddr_t) = X_mrt_ioctl; 4712763Swollman#endif 4722754Swollman 4732531Swollman/* 4749209Swollman * returns the packet, byte, rpf-failure count for the source group provided 4752531Swollman */ 4769209Swollmanstatic int 4772531Swollmanget_sg_cnt(req) 4782531Swollman register struct sioc_sg_req *req; 4792531Swollman{ 4802531Swollman register struct mfc *rt; 4812531Swollman int s; 4821541Srgrimes 4832531Swollman s = splnet(); 4842531Swollman MFCFIND(req->src.s_addr, req->grp.s_addr, rt); 4852531Swollman splx(s); 4869209Swollman if (rt != NULL) { 4879209Swollman req->pktcnt = rt->mfc_pkt_cnt; 4889209Swollman req->bytecnt = rt->mfc_byte_cnt; 4899209Swollman req->wrong_if = rt->mfc_wrong_if; 4909209Swollman } else 4919209Swollman req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; 4921541Srgrimes 4932531Swollman return 0; 4942531Swollman} 4951541Srgrimes 4962531Swollman/* 4979209Swollman * returns the input and output packet and byte counts on the vif provided 4982531Swollman */ 4999209Swollmanstatic int 5002531Swollmanget_vif_cnt(req) 5012531Swollman register struct sioc_vif_req *req; 5022531Swollman{ 5032531Swollman register vifi_t vifi = req->vifi; 5041541Srgrimes 5059209Swollman if (vifi >= numvifs) return EINVAL; 5069209Swollman 5072531Swollman req->icount = viftable[vifi].v_pkt_in; 5082531Swollman req->ocount = viftable[vifi].v_pkt_out; 5099209Swollman req->ibytes = viftable[vifi].v_bytes_in; 5109209Swollman req->obytes = viftable[vifi].v_bytes_out; 5111541Srgrimes 5122531Swollman return 0; 5132531Swollman} 5142531Swollman 5151541Srgrimes/* 5161541Srgrimes * Enable multicast routing 5171541Srgrimes */ 51812296Sphkstatic int 5199209Swollmanip_mrouter_init(so, m) 5202531Swollman struct socket *so; 5219209Swollman struct mbuf *m; 5221541Srgrimes{ 5239209Swollman int *v; 5249209Swollman 5259209Swollman if (mrtdebug) 52611284Swollman log(LOG_DEBUG,"ip_mrouter_init: so_type = %d, pr_protocol = %d\n", 5279209Swollman so->so_type, so->so_proto->pr_protocol); 5289209Swollman 5292531Swollman if (so->so_type != SOCK_RAW || 5302531Swollman so->so_proto->pr_protocol != IPPROTO_IGMP) return EOPNOTSUPP; 5311541Srgrimes 5329209Swollman if (!m || (m->m_len != sizeof(int *))) 5339209Swollman return ENOPROTOOPT; 5349209Swollman 5359209Swollman v = mtod(m, int *); 5369209Swollman if (*v != 1) 5379209Swollman return ENOPROTOOPT; 5389209Swollman 5392531Swollman if (ip_mrouter != NULL) return EADDRINUSE; 5401541Srgrimes 5412531Swollman ip_mrouter = so; 5421541Srgrimes 5439209Swollman bzero((caddr_t)mfctable, sizeof(mfctable)); 5449209Swollman bzero((caddr_t)nexpire, sizeof(nexpire)); 5459209Swollman 5469209Swollman pim_assert = 0; 5479209Swollman 5489209Swollman timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); 5499209Swollman 5502531Swollman if (mrtdebug) 55111284Swollman log(LOG_DEBUG, "ip_mrouter_init\n"); 5522531Swollman 5532531Swollman return 0; 5541541Srgrimes} 5551541Srgrimes 5561541Srgrimes/* 5571541Srgrimes * Disable multicast routing 5581541Srgrimes */ 55912296Sphkstatic int 5602763SwollmanX_ip_mrouter_done() 5611541Srgrimes{ 5622531Swollman vifi_t vifi; 5632531Swollman int i; 5642531Swollman struct ifnet *ifp; 5652531Swollman struct ifreq ifr; 5662531Swollman struct mbuf *mb_rt; 5672531Swollman struct mbuf *m; 5682531Swollman struct rtdetq *rte; 5692531Swollman int s; 5701541Srgrimes 5712531Swollman s = splnet(); 5721541Srgrimes 5732531Swollman /* 5742531Swollman * For each phyint in use, disable promiscuous reception of all IP 5752531Swollman * multicasts. 5762531Swollman */ 5772531Swollman for (vifi = 0; vifi < numvifs; vifi++) { 5782531Swollman if (viftable[vifi].v_lcl_addr.s_addr != 0 && 5792531Swollman !(viftable[vifi].v_flags & VIFF_TUNNEL)) { 5802531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; 5812531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr 5822531Swollman = INADDR_ANY; 5832531Swollman ifp = viftable[vifi].v_ifp; 5842531Swollman (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); 5852531Swollman } 5862531Swollman } 5872531Swollman bzero((caddr_t)tbftable, sizeof(tbftable)); 5882531Swollman bzero((caddr_t)viftable, sizeof(viftable)); 5892531Swollman numvifs = 0; 5909209Swollman pim_assert = 0; 5912531Swollman 5929209Swollman untimeout(expire_upcalls, (caddr_t)NULL); 5939209Swollman 5942531Swollman /* 5959209Swollman * Free all multicast forwarding cache entries. 5962531Swollman */ 5979209Swollman for (i = 0; i < MFCTBLSIZ; i++) { 5989209Swollman mb_rt = mfctable[i]; 5999209Swollman while (mb_rt) { 6009209Swollman if (mb_rt->m_act != NULL) { 6019209Swollman while (mb_rt->m_act) { 6029209Swollman m = mb_rt->m_act; 6039209Swollman mb_rt->m_act = m->m_act; 6049209Swollman rte = mtod(m, struct rtdetq *); 6059209Swollman m_freem(rte->m); 6069209Swollman m_free(m); 6071541Srgrimes } 6082531Swollman } 6099209Swollman mb_rt = m_free(mb_rt); 6101541Srgrimes } 6119209Swollman } 6121541Srgrimes 6132531Swollman bzero((caddr_t)mfctable, sizeof(mfctable)); 6141541Srgrimes 6152531Swollman /* 6162531Swollman * Reset de-encapsulation cache 6172531Swollman */ 6182531Swollman last_encap_src = NULL; 6192531Swollman last_encap_vif = NULL; 6209209Swollman have_encap_tunnel = 0; 6219209Swollman 6222531Swollman ip_mrouter = NULL; 6232531Swollman 6242531Swollman splx(s); 6252531Swollman 6262531Swollman if (mrtdebug) 62711284Swollman log(LOG_DEBUG, "ip_mrouter_done\n"); 6282531Swollman 6292531Swollman return 0; 6301541Srgrimes} 6311541Srgrimes 6322763Swollman#ifndef MROUTE_LKM 6332763Swollmanint (*ip_mrouter_done)(void) = X_ip_mrouter_done; 6342763Swollman#endif 6352754Swollman 6369209Swollmanstatic int 6379209Swollmanget_version(mb) 6389209Swollman struct mbuf *mb; 6399209Swollman{ 6409209Swollman int *v; 6419209Swollman 6429209Swollman v = mtod(mb, int *); 6439209Swollman 6449209Swollman *v = 0x0305; /* XXX !!!! */ 6459209Swollman mb->m_len = sizeof(int); 6469209Swollman 6479209Swollman return 0; 6489209Swollman} 6499209Swollman 6501541Srgrimes/* 6519209Swollman * Set PIM assert processing global 6529209Swollman */ 6539209Swollmanstatic int 6549209Swollmanset_assert(i) 6559209Swollman int *i; 6569209Swollman{ 6579209Swollman if ((*i != 1) && (*i != 0)) 6589209Swollman return EINVAL; 6599209Swollman 6609209Swollman pim_assert = *i; 6619209Swollman 6629209Swollman return 0; 6639209Swollman} 6649209Swollman 6659209Swollman/* 6669209Swollman * Get PIM assert processing global 6679209Swollman */ 6689209Swollmanstatic int 6699209Swollmanget_assert(m) 6709209Swollman struct mbuf *m; 6719209Swollman{ 6729209Swollman int *i; 6739209Swollman 6749209Swollman i = mtod(m, int *); 6759209Swollman 6769209Swollman *i = pim_assert; 6779209Swollman 6789209Swollman return 0; 6799209Swollman} 6809209Swollman 6819209Swollman/* 6821541Srgrimes * Add a vif to the vif table 6831541Srgrimes */ 6841541Srgrimesstatic int 6851541Srgrimesadd_vif(vifcp) 6862531Swollman register struct vifctl *vifcp; 6871541Srgrimes{ 6882531Swollman register struct vif *vifp = viftable + vifcp->vifc_vifi; 6893747Swollman static struct sockaddr_in sin = {sizeof sin, AF_INET}; 6902531Swollman struct ifaddr *ifa; 6912531Swollman struct ifnet *ifp; 6922531Swollman struct ifreq ifr; 6932531Swollman int error, s; 6942531Swollman struct tbf *v_tbf = tbftable + vifcp->vifc_vifi; 6951541Srgrimes 6962531Swollman if (vifcp->vifc_vifi >= MAXVIFS) return EINVAL; 6972531Swollman if (vifp->v_lcl_addr.s_addr != 0) return EADDRINUSE; 6981541Srgrimes 6992531Swollman /* Find the interface with an address in AF_INET family */ 7002531Swollman sin.sin_addr = vifcp->vifc_lcl_addr; 7012531Swollman ifa = ifa_ifwithaddr((struct sockaddr *)&sin); 7022531Swollman if (ifa == 0) return EADDRNOTAVAIL; 7032531Swollman ifp = ifa->ifa_ifp; 7041541Srgrimes 7052531Swollman if (vifcp->vifc_flags & VIFF_TUNNEL) { 7062531Swollman if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) { 7079209Swollman /* 7089209Swollman * An encapsulating tunnel is wanted. Tell ipip_input() to 7099209Swollman * start paying attention to encapsulated packets. 7109209Swollman */ 7119209Swollman if (have_encap_tunnel == 0) { 7129209Swollman have_encap_tunnel = 1; 7139209Swollman for (s = 0; s < MAXVIFS; ++s) { 7149209Swollman multicast_decap_if[s].if_name = "mdecap"; 7159209Swollman multicast_decap_if[s].if_unit = s; 7169209Swollman } 7171541Srgrimes } 7189209Swollman /* 7199209Swollman * Set interface to fake encapsulator interface 7209209Swollman */ 7219209Swollman ifp = &multicast_decap_if[vifcp->vifc_vifi]; 7229209Swollman /* 7239209Swollman * Prepare cached route entry 7249209Swollman */ 7259209Swollman bzero(&vifp->v_route, sizeof(vifp->v_route)); 7262531Swollman } else { 72711284Swollman log(LOG_ERR, "source routed tunnels not supported\n"); 7289209Swollman return EOPNOTSUPP; 7291541Srgrimes } 7302531Swollman } else { 7312531Swollman /* Make sure the interface supports multicast */ 7322531Swollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 7332531Swollman return EOPNOTSUPP; 7341541Srgrimes 7352531Swollman /* Enable promiscuous reception of all IP multicasts from the if */ 7362531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; 7372531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY; 7382531Swollman s = splnet(); 7392531Swollman error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); 7402531Swollman splx(s); 7412531Swollman if (error) 7422531Swollman return error; 7432531Swollman } 7441541Srgrimes 7452531Swollman s = splnet(); 7462531Swollman /* define parameters for the tbf structure */ 7472531Swollman vifp->v_tbf = v_tbf; 74810203Swollman GET_TIME(vifp->v_tbf->tbf_last_pkt_t); 74910203Swollman vifp->v_tbf->tbf_n_tok = 0; 75010203Swollman vifp->v_tbf->tbf_q_len = 0; 75110203Swollman vifp->v_tbf->tbf_max_q_len = MAXQSIZE; 75210203Swollman vifp->v_tbf->tbf_q = vifp->v_tbf->tbf_t = NULL; 7531541Srgrimes 7542531Swollman vifp->v_flags = vifcp->vifc_flags; 7552531Swollman vifp->v_threshold = vifcp->vifc_threshold; 7562531Swollman vifp->v_lcl_addr = vifcp->vifc_lcl_addr; 7572531Swollman vifp->v_rmt_addr = vifcp->vifc_rmt_addr; 7582531Swollman vifp->v_ifp = ifp; 75910203Swollman /* scaling up here allows division by 1024 in critical code */ 76010203Swollman vifp->v_rate_limit= vifcp->vifc_rate_limit * 1024 / 1000; 7619209Swollman vifp->v_rsvp_on = 0; 7629209Swollman vifp->v_rsvpd = NULL; 7632531Swollman /* initialize per vif pkt counters */ 7642531Swollman vifp->v_pkt_in = 0; 7652531Swollman vifp->v_pkt_out = 0; 7669209Swollman vifp->v_bytes_in = 0; 7679209Swollman vifp->v_bytes_out = 0; 7682531Swollman splx(s); 7692531Swollman 7702531Swollman /* Adjust numvifs up if the vifi is higher than numvifs */ 7712531Swollman if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1; 7722531Swollman 7732531Swollman if (mrtdebug) 77411284Swollman log(LOG_DEBUG, "add_vif #%d, lcladdr %x, %s %x, thresh %x, rate %d\n", 7759209Swollman vifcp->vifc_vifi, 7762531Swollman ntohl(vifcp->vifc_lcl_addr.s_addr), 7772531Swollman (vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask", 7782531Swollman ntohl(vifcp->vifc_rmt_addr.s_addr), 7792531Swollman vifcp->vifc_threshold, 7809209Swollman vifcp->vifc_rate_limit); 7812531Swollman 7822531Swollman return 0; 7831541Srgrimes} 7841541Srgrimes 7851541Srgrimes/* 7861541Srgrimes * Delete a vif from the vif table 7871541Srgrimes */ 7881541Srgrimesstatic int 7891541Srgrimesdel_vif(vifip) 7902531Swollman vifi_t *vifip; 7911541Srgrimes{ 7922531Swollman register struct vif *vifp = viftable + *vifip; 7932531Swollman register vifi_t vifi; 79410203Swollman register struct mbuf *m; 7952531Swollman struct ifnet *ifp; 7962531Swollman struct ifreq ifr; 7972531Swollman int s; 7981541Srgrimes 7992531Swollman if (*vifip >= numvifs) return EINVAL; 8002531Swollman if (vifp->v_lcl_addr.s_addr == 0) return EADDRNOTAVAIL; 8011541Srgrimes 8022531Swollman s = splnet(); 8031541Srgrimes 8042531Swollman if (!(vifp->v_flags & VIFF_TUNNEL)) { 8052531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; 8062531Swollman ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY; 8072531Swollman ifp = vifp->v_ifp; 8082531Swollman (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); 8092531Swollman } 8101541Srgrimes 8112531Swollman if (vifp == last_encap_vif) { 8122531Swollman last_encap_vif = 0; 8132531Swollman last_encap_src = 0; 8142531Swollman } 8151541Srgrimes 81610203Swollman /* 81710203Swollman * Free packets queued at the interface 81810203Swollman */ 81910203Swollman while (vifp->v_tbf->tbf_q) { 82010203Swollman m = vifp->v_tbf->tbf_q; 82110203Swollman vifp->v_tbf->tbf_q = m->m_act; 82210203Swollman m_freem(m); 82310203Swollman } 82410203Swollman 8252531Swollman bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf))); 8262531Swollman bzero((caddr_t)vifp, sizeof (*vifp)); 8271541Srgrimes 8282531Swollman /* Adjust numvifs down */ 8292531Swollman for (vifi = numvifs; vifi > 0; vifi--) 8302531Swollman if (viftable[vifi-1].v_lcl_addr.s_addr != 0) break; 8312531Swollman numvifs = vifi; 8322531Swollman 8332531Swollman splx(s); 8342531Swollman 8352531Swollman if (mrtdebug) 83611284Swollman log(LOG_DEBUG, "del_vif %d, numvifs %d\n", *vifip, numvifs); 8372531Swollman 8382531Swollman return 0; 8391541Srgrimes} 8401541Srgrimes 8411541Srgrimes/* 8422531Swollman * Add an mfc entry 8431541Srgrimes */ 8441541Srgrimesstatic int 8452531Swollmanadd_mfc(mfccp) 8462531Swollman struct mfcctl *mfccp; 8471541Srgrimes{ 8482531Swollman struct mfc *rt; 8492531Swollman register struct mbuf *mb_rt; 8502531Swollman u_long hash; 8512531Swollman struct mbuf *mb_ntry; 8522531Swollman struct rtdetq *rte; 8532531Swollman register u_short nstl; 8542531Swollman int s; 8552531Swollman int i; 8561541Srgrimes 8579209Swollman MFCFIND(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr, rt); 8581541Srgrimes 8592531Swollman /* If an entry already exists, just update the fields */ 8602531Swollman if (rt) { 8619209Swollman if (mrtdebug & DEBUG_MFC) 86211284Swollman log(LOG_DEBUG,"add_mfc update o %x g %x p %x\n", 8632531Swollman ntohl(mfccp->mfcc_origin.s_addr), 8642531Swollman ntohl(mfccp->mfcc_mcastgrp.s_addr), 8652531Swollman mfccp->mfcc_parent); 8661541Srgrimes 8671541Srgrimes s = splnet(); 8682531Swollman rt->mfc_parent = mfccp->mfcc_parent; 8692531Swollman for (i = 0; i < numvifs; i++) 8709209Swollman rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 8712531Swollman splx(s); 8722531Swollman return 0; 8732531Swollman } 8741541Srgrimes 8759209Swollman /* 8762531Swollman * Find the entry for which the upcall was made and update 8772531Swollman */ 8782531Swollman s = splnet(); 8799209Swollman hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); 8809209Swollman for (mb_rt = mfctable[hash], nstl = 0; mb_rt; mb_rt = mb_rt->m_next) { 8811541Srgrimes 8822531Swollman rt = mtod(mb_rt, struct mfc *); 8839209Swollman if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && 8842531Swollman (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) && 8852531Swollman (mb_rt->m_act != NULL)) { 8869209Swollman 8879209Swollman if (nstl++) 88811284Swollman log(LOG_ERR, "add_mfc %s o %x g %x p %x dbx %x\n", 8899209Swollman "multiple kernel entries", 8909209Swollman ntohl(mfccp->mfcc_origin.s_addr), 8919209Swollman ntohl(mfccp->mfcc_mcastgrp.s_addr), 8929209Swollman mfccp->mfcc_parent, mb_rt->m_act); 8931541Srgrimes 8949209Swollman if (mrtdebug & DEBUG_MFC) 89511284Swollman log(LOG_DEBUG,"add_mfc o %x g %x p %x dbg %x\n", 8969209Swollman ntohl(mfccp->mfcc_origin.s_addr), 8979209Swollman ntohl(mfccp->mfcc_mcastgrp.s_addr), 8989209Swollman mfccp->mfcc_parent, mb_rt->m_act); 8991541Srgrimes 9009209Swollman rt->mfc_origin = mfccp->mfcc_origin; 9019209Swollman rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; 9029209Swollman rt->mfc_parent = mfccp->mfcc_parent; 9039209Swollman for (i = 0; i < numvifs; i++) 9049209Swollman rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 9059209Swollman /* initialize pkt counters per src-grp */ 9069209Swollman rt->mfc_pkt_cnt = 0; 9079209Swollman rt->mfc_byte_cnt = 0; 9089209Swollman rt->mfc_wrong_if = 0; 9099209Swollman rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; 9102531Swollman 9119209Swollman rt->mfc_expire = 0; /* Don't clean this guy up */ 9129209Swollman nexpire[hash]--; 9132531Swollman 9142531Swollman /* free packets Qed at the end of this entry */ 9152531Swollman while (mb_rt->m_act) { 9162531Swollman mb_ntry = mb_rt->m_act; 9172531Swollman rte = mtod(mb_ntry, struct rtdetq *); 9189209Swollman/* #ifdef RSVP_ISI */ 9199209Swollman ip_mdq(rte->m, rte->ifp, rt, -1); 9209209Swollman/* #endif */ 9212531Swollman mb_rt->m_act = mb_ntry->m_act; 9222531Swollman m_freem(rte->m); 9239209Swollman#ifdef UPCALL_TIMING 9249209Swollman collate(&(rte->t)); 9259209Swollman#endif /* UPCALL_TIMING */ 9262531Swollman m_free(mb_ntry); 9272531Swollman } 9281541Srgrimes } 9292531Swollman } 9301541Srgrimes 9312531Swollman /* 9322531Swollman * It is possible that an entry is being inserted without an upcall 9332531Swollman */ 9342531Swollman if (nstl == 0) { 9359209Swollman if (mrtdebug & DEBUG_MFC) 93611284Swollman log(LOG_DEBUG,"add_mfc no upcall h %d o %x g %x p %x\n", 9372531Swollman hash, ntohl(mfccp->mfcc_origin.s_addr), 9382531Swollman ntohl(mfccp->mfcc_mcastgrp.s_addr), 9392531Swollman mfccp->mfcc_parent); 9409209Swollman 9419209Swollman for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) { 9429209Swollman 9432531Swollman rt = mtod(mb_rt, struct mfc *); 9449209Swollman if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && 9452531Swollman (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) { 9461541Srgrimes 9472531Swollman rt->mfc_origin = mfccp->mfcc_origin; 9482531Swollman rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; 9492531Swollman rt->mfc_parent = mfccp->mfcc_parent; 9502531Swollman for (i = 0; i < numvifs; i++) 9519209Swollman rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 9522531Swollman /* initialize pkt counters per src-grp */ 9532531Swollman rt->mfc_pkt_cnt = 0; 9549209Swollman rt->mfc_byte_cnt = 0; 9559209Swollman rt->mfc_wrong_if = 0; 9569209Swollman rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; 9579209Swollman if (rt->mfc_expire) 9589209Swollman nexpire[hash]--; 9599209Swollman rt->mfc_expire = 0; 9602531Swollman } 9612531Swollman } 9622531Swollman if (mb_rt == NULL) { 9632531Swollman /* no upcall, so make a new entry */ 9642531Swollman MGET(mb_rt, M_DONTWAIT, MT_MRTABLE); 9652531Swollman if (mb_rt == NULL) { 9662531Swollman splx(s); 9672531Swollman return ENOBUFS; 9682531Swollman } 9699209Swollman 9702531Swollman rt = mtod(mb_rt, struct mfc *); 9719209Swollman 9722531Swollman /* insert new entry at head of hash chain */ 9732531Swollman rt->mfc_origin = mfccp->mfcc_origin; 9742531Swollman rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; 9752531Swollman rt->mfc_parent = mfccp->mfcc_parent; 9762531Swollman for (i = 0; i < numvifs; i++) 9779209Swollman rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; 9782531Swollman /* initialize pkt counters per src-grp */ 9792531Swollman rt->mfc_pkt_cnt = 0; 9809209Swollman rt->mfc_byte_cnt = 0; 9819209Swollman rt->mfc_wrong_if = 0; 9829209Swollman rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; 9839209Swollman rt->mfc_expire = 0; 9849209Swollman 9852531Swollman /* link into table */ 9862531Swollman mb_rt->m_next = mfctable[hash]; 9872531Swollman mfctable[hash] = mb_rt; 9882531Swollman mb_rt->m_act = NULL; 9892531Swollman } 9902531Swollman } 9912531Swollman splx(s); 9922531Swollman return 0; 9931541Srgrimes} 9941541Srgrimes 9959209Swollman#ifdef UPCALL_TIMING 9961541Srgrimes/* 9979209Swollman * collect delay statistics on the upcalls 9989209Swollman */ 9999209Swollmanstatic void collate(t) 10009209Swollmanregister struct timeval *t; 10019209Swollman{ 10029209Swollman register u_long d; 10039209Swollman register struct timeval tp; 10049209Swollman register u_long delta; 10059209Swollman 10069209Swollman GET_TIME(tp); 10079209Swollman 10089209Swollman if (TV_LT(*t, tp)) 10099209Swollman { 10109209Swollman TV_DELTA(tp, *t, delta); 10119209Swollman 10129209Swollman d = delta >> 10; 10139209Swollman if (d > 50) 10149209Swollman d = 50; 10159209Swollman 10169209Swollman ++upcall_data[d]; 10179209Swollman } 10189209Swollman} 10199209Swollman#endif /* UPCALL_TIMING */ 10209209Swollman 10219209Swollman/* 10222531Swollman * Delete an mfc entry 10231541Srgrimes */ 10241541Srgrimesstatic int 10252531Swollmandel_mfc(mfccp) 10269209Swollman struct mfcctl *mfccp; 10271541Srgrimes{ 10282531Swollman struct in_addr origin; 10292531Swollman struct in_addr mcastgrp; 10302531Swollman struct mfc *rt; 10312531Swollman struct mbuf *mb_rt; 10329209Swollman struct mbuf **nptr; 10332531Swollman u_long hash; 103411921Sphk int s; 10351541Srgrimes 10362531Swollman origin = mfccp->mfcc_origin; 10372531Swollman mcastgrp = mfccp->mfcc_mcastgrp; 10389209Swollman hash = MFCHASH(origin.s_addr, mcastgrp.s_addr); 10391541Srgrimes 10409209Swollman if (mrtdebug & DEBUG_MFC) 104111284Swollman log(LOG_DEBUG,"del_mfc orig %x mcastgrp %x\n", 10422531Swollman ntohl(origin.s_addr), ntohl(mcastgrp.s_addr)); 10431541Srgrimes 10449209Swollman s = splnet(); 10459209Swollman 10469209Swollman nptr = &mfctable[hash]; 10479209Swollman while ((mb_rt = *nptr) != NULL) { 10482531Swollman rt = mtod(mb_rt, struct mfc *); 10492531Swollman if (origin.s_addr == rt->mfc_origin.s_addr && 10502531Swollman mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr && 10512531Swollman mb_rt->m_act == NULL) 10522531Swollman break; 10539209Swollman 10549209Swollman nptr = &mb_rt->m_next; 10552531Swollman } 10562531Swollman if (mb_rt == NULL) { 10579209Swollman splx(s); 10589209Swollman return EADDRNOTAVAIL; 10592531Swollman } 10601541Srgrimes 10619209Swollman MFREE(mb_rt, *nptr); 10621541Srgrimes 10632531Swollman splx(s); 10642531Swollman 10652531Swollman return 0; 10661541Srgrimes} 10671541Srgrimes 10681541Srgrimes/* 10699209Swollman * Send a message to mrouted on the multicast routing socket 10709209Swollman */ 10719209Swollmanstatic int 10729209Swollmansocket_send(s, mm, src) 10739209Swollman struct socket *s; 10749209Swollman struct mbuf *mm; 10759209Swollman struct sockaddr_in *src; 10769209Swollman{ 10779209Swollman if (s) { 10789209Swollman if (sbappendaddr(&s->so_rcv, 10799209Swollman (struct sockaddr *)src, 10809209Swollman mm, (struct mbuf *)0) != 0) { 10819209Swollman sorwakeup(s); 10829209Swollman return 0; 10839209Swollman } 10849209Swollman } 10859209Swollman m_freem(mm); 10869209Swollman return -1; 10879209Swollman} 10889209Swollman 10899209Swollman/* 10902531Swollman * IP multicast forwarding function. This function assumes that the packet 10912531Swollman * pointed to by "ip" has arrived on (or is about to be sent to) the interface 10922531Swollman * pointed to by "ifp", and the packet is to be relayed to other networks 10932531Swollman * that have members of the packet's destination IP multicast group. 10942531Swollman * 10959209Swollman * The packet is returned unscathed to the caller, unless it is 10969209Swollman * erroneous, in which case a non-zero return value tells the caller to 10972531Swollman * discard it. 10981541Srgrimes */ 10992531Swollman 11002531Swollman#define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */ 11012531Swollman#define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */ 11022531Swollman 110312296Sphkstatic int 11042763SwollmanX_ip_mforward(ip, ifp, m, imo) 11052531Swollman register struct ip *ip; 11062531Swollman struct ifnet *ifp; 11072754Swollman struct mbuf *m; 11082531Swollman struct ip_moptions *imo; 11091541Srgrimes{ 111014549Sfenner register struct mfc *rt; 11112531Swollman register u_char *ipoptions; 11123747Swollman static struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; 11139209Swollman static int srctun = 0; 11142531Swollman register struct mbuf *mm; 11152531Swollman int s; 11169209Swollman vifi_t vifi; 11179209Swollman struct vif *vifp; 11181541Srgrimes 11199209Swollman if (mrtdebug & DEBUG_FORWARD) 112011284Swollman log(LOG_DEBUG, "ip_mforward: src %x, dst %x, ifp %x\n", 11219209Swollman ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), ifp); 11221541Srgrimes 11232531Swollman if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 || 11242531Swollman (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) { 11252531Swollman /* 11269209Swollman * Packet arrived via a physical interface or 11279209Swollman * an encapsulated tunnel. 11282531Swollman */ 11292531Swollman } else { 11302531Swollman /* 11312531Swollman * Packet arrived through a source-route tunnel. 11329209Swollman * Source-route tunnels are no longer supported. 11332531Swollman */ 11349209Swollman if ((srctun++ % 1000) == 0) 113511284Swollman log(LOG_ERR, "ip_mforward: received source-routed packet from %x\n", 11369209Swollman ntohl(ip->ip_src.s_addr)); 11378876Srgrimes 11389209Swollman return 1; 11399209Swollman } 11409209Swollman 11419209Swollman if ((imo) && ((vifi = imo->imo_multicast_vif) < numvifs)) { 11429209Swollman if (ip->ip_ttl < 255) 11439209Swollman ip->ip_ttl++; /* compensate for -1 in *_send routines */ 11449209Swollman if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { 11459209Swollman vifp = viftable + vifi; 114612296Sphk printf("Sending IPPROTO_RSVP from %lx to %lx on vif %d (%s%s%d)\n", 11479209Swollman ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), vifi, 11489209Swollman (vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "", 11499209Swollman vifp->v_ifp->if_name, vifp->v_ifp->if_unit); 11502531Swollman } 115114549Sfenner return (ip_mdq(m, ifp, NULL, vifi)); 11522531Swollman } 11539209Swollman if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { 115412296Sphk printf("Warning: IPPROTO_RSVP from %lx to %lx without vif option\n", 11559209Swollman ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr)); 11569728Swollman if(!imo) 11579728Swollman printf("In fact, no options were specified at all\n"); 11589209Swollman } 11592531Swollman 11602531Swollman /* 11612531Swollman * Don't forward a packet with time-to-live of zero or one, 11622531Swollman * or a packet destined to a local-only group. 11632531Swollman */ 11642531Swollman if (ip->ip_ttl <= 1 || 11652531Swollman ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP) 11669209Swollman return 0; 11672531Swollman 11682531Swollman /* 11692531Swollman * Determine forwarding vifs from the forwarding cache table 11702531Swollman */ 11712531Swollman s = splnet(); 11722531Swollman MFCFIND(ip->ip_src.s_addr, ip->ip_dst.s_addr, rt); 11732531Swollman 11742531Swollman /* Entry exists, so forward if necessary */ 11752531Swollman if (rt != NULL) { 11761541Srgrimes splx(s); 11779209Swollman return (ip_mdq(m, ifp, rt, -1)); 11789209Swollman } else { 11792531Swollman /* 11802531Swollman * If we don't have a route for packet's origin, 11812531Swollman * Make a copy of the packet & 11822531Swollman * send message to routing daemon 11832531Swollman */ 11842531Swollman 11852531Swollman register struct mbuf *mb_rt; 11862531Swollman register struct mbuf *mb_ntry; 11872531Swollman register struct mbuf *mb0; 11882531Swollman register struct rtdetq *rte; 11892531Swollman register struct mbuf *rte_m; 11902531Swollman register u_long hash; 11919209Swollman register int npkts; 119214549Sfenner int hlen = ip->ip_hl << 2; 11939209Swollman#ifdef UPCALL_TIMING 11949209Swollman struct timeval tp; 11952531Swollman 11969209Swollman GET_TIME(tp); 11979209Swollman#endif 11989209Swollman 11992531Swollman mrtstat.mrts_no_route++; 12009209Swollman if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC)) 120111284Swollman log(LOG_DEBUG, "ip_mforward: no rte s %x g %x\n", 12022531Swollman ntohl(ip->ip_src.s_addr), 12032531Swollman ntohl(ip->ip_dst.s_addr)); 12042531Swollman 12059209Swollman /* 12069209Swollman * Allocate mbufs early so that we don't do extra work if we are 120714549Sfenner * just going to fail anyway. Make sure to pullup the header so 120814549Sfenner * that other people can't step on it. 12099209Swollman */ 12109209Swollman MGET(mb_ntry, M_DONTWAIT, MT_DATA); 12119209Swollman if (mb_ntry == NULL) { 12129209Swollman splx(s); 12139209Swollman return ENOBUFS; 12149209Swollman } 12159209Swollman mb0 = m_copy(m, 0, M_COPYALL); 121614549Sfenner if (mb0 && (M_HASCL(mb0) || mb0->m_len < hlen)) 121714549Sfenner mb0 = m_pullup(mb0, hlen); 12189209Swollman if (mb0 == NULL) { 12199209Swollman m_free(mb_ntry); 12209209Swollman splx(s); 12219209Swollman return ENOBUFS; 12229209Swollman } 12239209Swollman 12242531Swollman /* is there an upcall waiting for this packet? */ 12259209Swollman hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr); 12262531Swollman for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) { 12272531Swollman rt = mtod(mb_rt, struct mfc *); 12289209Swollman if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) && 12292531Swollman (ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) && 12302531Swollman (mb_rt->m_act != NULL)) 12312531Swollman break; 12322531Swollman } 12332531Swollman 12342531Swollman if (mb_rt == NULL) { 12359209Swollman int i; 12369209Swollman struct igmpmsg *im; 12379209Swollman 12382531Swollman /* no upcall, so make a new entry */ 12392531Swollman MGET(mb_rt, M_DONTWAIT, MT_MRTABLE); 12402531Swollman if (mb_rt == NULL) { 12419209Swollman m_free(mb_ntry); 12429266Swollman m_freem(mb0); 12432531Swollman splx(s); 12442531Swollman return ENOBUFS; 12452531Swollman } 12469209Swollman /* Make a copy of the header to send to the user level process */ 12479209Swollman mm = m_copy(m, 0, hlen); 12489209Swollman if (mm == NULL) { 12499209Swollman m_free(mb_ntry); 12509266Swollman m_freem(mb0); 12519209Swollman m_free(mb_rt); 12529209Swollman splx(s); 12539209Swollman return ENOBUFS; 12549209Swollman } 12552531Swollman 12569209Swollman /* 12579209Swollman * Send message to routing daemon to install 12589209Swollman * a route into the kernel table 12599209Swollman */ 12609209Swollman k_igmpsrc.sin_addr = ip->ip_src; 12619209Swollman 12629209Swollman im = mtod(mm, struct igmpmsg *); 12639209Swollman im->im_msgtype = IGMPMSG_NOCACHE; 12649209Swollman im->im_mbz = 0; 12659209Swollman 12669209Swollman mrtstat.mrts_upcalls++; 12679209Swollman 12689209Swollman if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) { 126911284Swollman log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n"); 12709209Swollman ++mrtstat.mrts_upq_sockfull; 12719209Swollman m_free(mb_ntry); 12729266Swollman m_freem(mb0); 12739209Swollman m_free(mb_rt); 12749209Swollman splx(s); 12759209Swollman return ENOBUFS; 12769209Swollman } 12779209Swollman 12782531Swollman rt = mtod(mb_rt, struct mfc *); 12792531Swollman 12802531Swollman /* insert new entry at head of hash chain */ 12812531Swollman rt->mfc_origin.s_addr = ip->ip_src.s_addr; 12822531Swollman rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr; 12839209Swollman rt->mfc_expire = UPCALL_EXPIRE; 12849209Swollman nexpire[hash]++; 12859209Swollman for (i = 0; i < numvifs; i++) 12869209Swollman rt->mfc_ttls[i] = 0; 12879209Swollman rt->mfc_parent = -1; 12882531Swollman 12892531Swollman /* link into table */ 12902531Swollman mb_rt->m_next = mfctable[hash]; 12912531Swollman mfctable[hash] = mb_rt; 12922531Swollman mb_rt->m_act = NULL; 12932531Swollman 12949209Swollman rte_m = mb_rt; 12959209Swollman } else { 12969209Swollman /* determine if q has overflowed */ 12979209Swollman for (rte_m = mb_rt, npkts = 0; rte_m->m_act; rte_m = rte_m->m_act) 12989209Swollman npkts++; 12992531Swollman 13009209Swollman if (npkts > MAX_UPQ) { 13019209Swollman mrtstat.mrts_upq_ovflw++; 13029209Swollman m_free(mb_ntry); 13039266Swollman m_freem(mb0); 13049209Swollman splx(s); 13059209Swollman return 0; 13069209Swollman } 13072531Swollman } 13082531Swollman 13092531Swollman mb_ntry->m_act = NULL; 13102531Swollman rte = mtod(mb_ntry, struct rtdetq *); 13112531Swollman 13122531Swollman rte->m = mb0; 13132531Swollman rte->ifp = ifp; 13149209Swollman#ifdef UPCALL_TIMING 13159209Swollman rte->t = tp; 13169209Swollman#endif 13172531Swollman 13189209Swollman /* Add this entry to the end of the queue */ 13199209Swollman rte_m->m_act = mb_ntry; 13202531Swollman 13212531Swollman splx(s); 13222531Swollman 13232531Swollman return 0; 13249209Swollman } 13251541Srgrimes} 13261541Srgrimes 13272763Swollman#ifndef MROUTE_LKM 13282754Swollmanint (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, 13292763Swollman struct ip_moptions *) = X_ip_mforward; 13302763Swollman#endif 13312754Swollman 13321541Srgrimes/* 13332531Swollman * Clean up the cache entry if upcall is not serviced 13341541Srgrimes */ 13352531Swollmanstatic void 13369209Swollmanexpire_upcalls(void *unused) 13371541Srgrimes{ 13389209Swollman struct mbuf *mb_rt, *m, **nptr; 13392531Swollman struct rtdetq *rte; 13409209Swollman struct mfc *mfc; 13419209Swollman int i; 13422531Swollman int s; 13431541Srgrimes 13442531Swollman s = splnet(); 13459209Swollman for (i = 0; i < MFCTBLSIZ; i++) { 13469209Swollman if (nexpire[i] == 0) 13479209Swollman continue; 13489209Swollman nptr = &mfctable[i]; 13499209Swollman for (mb_rt = *nptr; mb_rt != NULL; mb_rt = *nptr) { 13509209Swollman mfc = mtod(mb_rt, struct mfc *); 13512531Swollman 13529209Swollman /* 13539209Swollman * Skip real cache entries 13549209Swollman * Make sure it wasn't marked to not expire (shouldn't happen) 13559209Swollman * If it expires now 13569209Swollman */ 13579209Swollman if (mb_rt->m_act != NULL && 13589209Swollman mfc->mfc_expire != 0 && 13599209Swollman --mfc->mfc_expire == 0) { 13609209Swollman if (mrtdebug & DEBUG_EXPIRE) 136111284Swollman log(LOG_DEBUG, "expire_upcalls: expiring (%x %x)\n", 13629209Swollman ntohl(mfc->mfc_origin.s_addr), 13639209Swollman ntohl(mfc->mfc_mcastgrp.s_addr)); 13649209Swollman /* 13659209Swollman * drop all the packets 13669209Swollman * free the mbuf with the pkt, if, timing info 13679209Swollman */ 13689209Swollman while (mb_rt->m_act) { 13699209Swollman m = mb_rt->m_act; 13709209Swollman mb_rt->m_act = m->m_act; 13719209Swollman 13729209Swollman rte = mtod(m, struct rtdetq *); 13739209Swollman m_freem(rte->m); 13749209Swollman m_free(m); 13759209Swollman } 13769209Swollman ++mrtstat.mrts_cache_cleanups; 13779209Swollman nexpire[i]--; 13782531Swollman 13799209Swollman MFREE(mb_rt, *nptr); 13809209Swollman } else { 13819209Swollman nptr = &mb_rt->m_next; 13829209Swollman } 13839209Swollman } 13842531Swollman } 13852531Swollman splx(s); 13869209Swollman timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); 13871541Srgrimes} 13881541Srgrimes 13891541Srgrimes/* 13902531Swollman * Packet forwarding routine once entry in the cache is made 13911541Srgrimes */ 13921541Srgrimesstatic int 13939209Swollmanip_mdq(m, ifp, rt, xmt_vif) 13942531Swollman register struct mbuf *m; 13952531Swollman register struct ifnet *ifp; 13962531Swollman register struct mfc *rt; 13979209Swollman register vifi_t xmt_vif; 13981541Srgrimes{ 13992531Swollman register struct ip *ip = mtod(m, struct ip *); 14002531Swollman register vifi_t vifi; 14012531Swollman register struct vif *vifp; 14029209Swollman register int plen = ntohs(ip->ip_len); 14031541Srgrimes 14049209Swollman/* 14059209Swollman * Macro to send packet on vif. Since RSVP packets don't get counted on 14069209Swollman * input, they shouldn't get counted on output, so statistics keeping is 14079209Swollman * seperate. 14089209Swollman */ 14099209Swollman#define MC_SEND(ip,vifp,m) { \ 14109209Swollman if ((vifp)->v_flags & VIFF_TUNNEL) \ 14119209Swollman encap_send((ip), (vifp), (m)); \ 14129209Swollman else \ 14139209Swollman phyint_send((ip), (vifp), (m)); \ 14149209Swollman} 14159209Swollman 14162531Swollman /* 14179209Swollman * If xmt_vif is not -1, send on only the requested vif. 14189209Swollman * 14199209Swollman * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.) 14209209Swollman */ 14219209Swollman if (xmt_vif < numvifs) { 14229209Swollman MC_SEND(ip, viftable + xmt_vif, m); 14239209Swollman return 1; 14249209Swollman } 14259209Swollman 14269209Swollman /* 14272531Swollman * Don't forward if it didn't arrive from the parent vif for its origin. 14282531Swollman */ 14292531Swollman vifi = rt->mfc_parent; 14309209Swollman if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) { 14312531Swollman /* came in the wrong interface */ 14329209Swollman if (mrtdebug & DEBUG_FORWARD) 143311284Swollman log(LOG_DEBUG, "wrong if: ifp %x vifi %d vififp %x\n", 14349209Swollman ifp, vifi, viftable[vifi].v_ifp); 14352531Swollman ++mrtstat.mrts_wrong_if; 14369209Swollman ++rt->mfc_wrong_if; 14379209Swollman /* 14389209Swollman * If we are doing PIM assert processing, and we are forwarding 14399209Swollman * packets on this interface, and it is a broadcast medium 14409209Swollman * interface (and not a tunnel), send a message to the routing daemon. 14419209Swollman */ 14429209Swollman if (pim_assert && rt->mfc_ttls[vifi] && 14439209Swollman (ifp->if_flags & IFF_BROADCAST) && 14449209Swollman !(viftable[vifi].v_flags & VIFF_TUNNEL)) { 14459209Swollman struct sockaddr_in k_igmpsrc; 14469209Swollman struct mbuf *mm; 14479209Swollman struct igmpmsg *im; 14489209Swollman int hlen = ip->ip_hl << 2; 14499209Swollman struct timeval now; 14509209Swollman register u_long delta; 14519209Swollman 14529209Swollman GET_TIME(now); 14539209Swollman 14549209Swollman TV_DELTA(rt->mfc_last_assert, now, delta); 14559209Swollman 14569209Swollman if (delta > ASSERT_MSG_TIME) { 14579209Swollman mm = m_copy(m, 0, hlen); 14589209Swollman if (mm && (M_HASCL(mm) || mm->m_len < hlen)) 14599209Swollman mm = m_pullup(mm, hlen); 14609209Swollman if (mm == NULL) { 14619209Swollman return ENOBUFS; 14629209Swollman } 14639209Swollman 14649209Swollman rt->mfc_last_assert = now; 14659209Swollman 14669209Swollman im = mtod(mm, struct igmpmsg *); 14679209Swollman im->im_msgtype = IGMPMSG_WRONGVIF; 14689209Swollman im->im_mbz = 0; 14699209Swollman im->im_vif = vifi; 14709209Swollman 14719209Swollman k_igmpsrc.sin_addr = im->im_src; 14729209Swollman 14739334Swollman socket_send(ip_mrouter, mm, &k_igmpsrc); 14749209Swollman } 14759209Swollman } 14769209Swollman return 0; 14772531Swollman } 14781541Srgrimes 14799209Swollman /* If I sourced this packet, it counts as output, else it was input. */ 14809209Swollman if (ip->ip_src.s_addr == viftable[vifi].v_lcl_addr.s_addr) { 14819209Swollman viftable[vifi].v_pkt_out++; 14829209Swollman viftable[vifi].v_bytes_out += plen; 14839209Swollman } else { 14849209Swollman viftable[vifi].v_pkt_in++; 14859209Swollman viftable[vifi].v_bytes_in += plen; 14869209Swollman } 14872531Swollman rt->mfc_pkt_cnt++; 14889209Swollman rt->mfc_byte_cnt += plen; 14891541Srgrimes 14902531Swollman /* 14912531Swollman * For each vif, decide if a copy of the packet should be forwarded. 14922531Swollman * Forward if: 14932531Swollman * - the ttl exceeds the vif's threshold 14942531Swollman * - there are group members downstream on interface 14952531Swollman */ 14962531Swollman for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) 14972531Swollman if ((rt->mfc_ttls[vifi] > 0) && 14989209Swollman (ip->ip_ttl > rt->mfc_ttls[vifi])) { 14999209Swollman vifp->v_pkt_out++; 15009209Swollman vifp->v_bytes_out += plen; 15012531Swollman MC_SEND(ip, vifp, m); 15029209Swollman } 15032531Swollman 15042531Swollman return 0; 15051541Srgrimes} 15061541Srgrimes 15079209Swollman/* 15089209Swollman * check if a vif number is legal/ok. This is used by ip_output, to export 15099209Swollman * numvifs there, 15101541Srgrimes */ 151112296Sphkstatic int 15122763SwollmanX_legal_vif_num(vif) 15132531Swollman int vif; 15149209Swollman{ 15159209Swollman if (vif >= 0 && vif < numvifs) 15162531Swollman return(1); 15172531Swollman else 15182531Swollman return(0); 15192531Swollman} 15202531Swollman 15212763Swollman#ifndef MROUTE_LKM 15222763Swollmanint (*legal_vif_num)(int) = X_legal_vif_num; 15232763Swollman#endif 15242754Swollman 15259209Swollman/* 15269209Swollman * Return the local address used by this vif 15279209Swollman */ 152812296Sphkstatic u_long 15299209SwollmanX_ip_mcast_src(vifi) 15309209Swollman int vifi; 15319209Swollman{ 15329209Swollman if (vifi >= 0 && vifi < numvifs) 15339209Swollman return viftable[vifi].v_lcl_addr.s_addr; 15349209Swollman else 15359209Swollman return INADDR_ANY; 15369209Swollman} 15379209Swollman 15389209Swollman#ifndef MROUTE_LKM 15399209Swollmanu_long (*ip_mcast_src)(int) = X_ip_mcast_src; 15409209Swollman#endif 15419209Swollman 15422531Swollmanstatic void 15432531Swollmanphyint_send(ip, vifp, m) 15442531Swollman struct ip *ip; 15452531Swollman struct vif *vifp; 15462531Swollman struct mbuf *m; 15471541Srgrimes{ 15482531Swollman register struct mbuf *mb_copy; 15499209Swollman register int hlen = ip->ip_hl << 2; 15501541Srgrimes 15513571Swollman /* 15529209Swollman * Make a new reference to the packet; make sure that 15539209Swollman * the IP header is actually copied, not just referenced, 15549209Swollman * so that ip_output() only scribbles on the copy. 15553571Swollman */ 15569209Swollman mb_copy = m_copy(m, 0, M_COPYALL); 15579209Swollman if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < hlen)) 15589209Swollman mb_copy = m_pullup(mb_copy, hlen); 15593571Swollman if (mb_copy == NULL) 15609209Swollman return; 15613571Swollman 15622531Swollman if (vifp->v_rate_limit <= 0) 156310203Swollman tbf_send_packet(vifp, mb_copy); 15642531Swollman else 156510203Swollman tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *), ip->ip_len); 15662531Swollman} 15671541Srgrimes 15682531Swollmanstatic void 15692531Swollmanencap_send(ip, vifp, m) 15702531Swollman register struct ip *ip; 15712531Swollman register struct vif *vifp; 15722531Swollman register struct mbuf *m; 15731541Srgrimes{ 15742531Swollman register struct mbuf *mb_copy; 15752531Swollman register struct ip *ip_copy; 15762531Swollman register int i, len = ip->ip_len; 15771541Srgrimes 15782531Swollman /* 15792531Swollman * copy the old packet & pullup it's IP header into the 15802531Swollman * new mbuf so we can modify it. Try to fill the new 15812531Swollman * mbuf since if we don't the ethernet driver will. 15822531Swollman */ 15832531Swollman MGET(mb_copy, M_DONTWAIT, MT_DATA); 15842531Swollman if (mb_copy == NULL) 15852531Swollman return; 15862531Swollman mb_copy->m_data += 16; 15872531Swollman mb_copy->m_len = sizeof(multicast_encap_iphdr); 15881541Srgrimes 15892531Swollman if ((mb_copy->m_next = m_copy(m, 0, M_COPYALL)) == NULL) { 15902531Swollman m_freem(mb_copy); 15912531Swollman return; 15922531Swollman } 15932531Swollman i = MHLEN - M_LEADINGSPACE(mb_copy); 15942531Swollman if (i > len) 15952531Swollman i = len; 15962531Swollman mb_copy = m_pullup(mb_copy, i); 15972531Swollman if (mb_copy == NULL) 15982531Swollman return; 15993571Swollman mb_copy->m_pkthdr.len = len + sizeof(multicast_encap_iphdr); 16001541Srgrimes 16012531Swollman /* 16022531Swollman * fill in the encapsulating IP header. 16032531Swollman */ 16042531Swollman ip_copy = mtod(mb_copy, struct ip *); 16052531Swollman *ip_copy = multicast_encap_iphdr; 16062531Swollman ip_copy->ip_id = htons(ip_id++); 16072531Swollman ip_copy->ip_len += len; 16082531Swollman ip_copy->ip_src = vifp->v_lcl_addr; 16092531Swollman ip_copy->ip_dst = vifp->v_rmt_addr; 16101541Srgrimes 16112531Swollman /* 16122531Swollman * turn the encapsulated IP header back into a valid one. 16132531Swollman */ 16142531Swollman ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr)); 16152531Swollman --ip->ip_ttl; 16162531Swollman HTONS(ip->ip_len); 16172531Swollman HTONS(ip->ip_off); 16182531Swollman ip->ip_sum = 0; 16192531Swollman#if defined(LBL) && !defined(ultrix) 16202531Swollman ip->ip_sum = ~oc_cksum((caddr_t)ip, ip->ip_hl << 2, 0); 16212531Swollman#else 16222531Swollman mb_copy->m_data += sizeof(multicast_encap_iphdr); 16232531Swollman ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2); 16242531Swollman mb_copy->m_data -= sizeof(multicast_encap_iphdr); 16252531Swollman#endif 16262531Swollman 16272531Swollman if (vifp->v_rate_limit <= 0) 162810203Swollman tbf_send_packet(vifp, mb_copy); 16292531Swollman else 163010203Swollman tbf_control(vifp, mb_copy, ip, ip_copy->ip_len); 16311541Srgrimes} 16321541Srgrimes 16331541Srgrimes/* 16342531Swollman * De-encapsulate a packet and feed it back through ip input (this 16352531Swollman * routine is called whenever IP gets a packet with proto type 16362531Swollman * ENCAP_PROTO and a local destination address). 16371541Srgrimes */ 16382531Swollmanvoid 16392763Swollman#ifdef MROUTE_LKM 16409209SwollmanX_ipip_input(m) 16412763Swollman#else 16429209Swollmanipip_input(m, iphlen) 16432763Swollman#endif 16449209Swollman register struct mbuf *m; 16459209Swollman int iphlen; 16462531Swollman{ 16472531Swollman struct ifnet *ifp = m->m_pkthdr.rcvif; 16482531Swollman register struct ip *ip = mtod(m, struct ip *); 16492531Swollman register int hlen = ip->ip_hl << 2; 16502531Swollman register int s; 16512531Swollman register struct ifqueue *ifq; 16522531Swollman register struct vif *vifp; 16531541Srgrimes 16549209Swollman if (!have_encap_tunnel) { 16559209Swollman rip_input(m); 16569209Swollman return; 16572531Swollman } 16582531Swollman /* 16592531Swollman * dump the packet if it's not to a multicast destination or if 16602531Swollman * we don't have an encapsulating tunnel with the source. 16612531Swollman * Note: This code assumes that the remote site IP address 16622531Swollman * uniquely identifies the tunnel (i.e., that this site has 16632531Swollman * at most one tunnel with the remote site). 16642531Swollman */ 16652531Swollman if (! IN_MULTICAST(ntohl(((struct ip *)((char *)ip + hlen))->ip_dst.s_addr))) { 16662531Swollman ++mrtstat.mrts_bad_tunnel; 16672531Swollman m_freem(m); 16682531Swollman return; 16692531Swollman } 16702531Swollman if (ip->ip_src.s_addr != last_encap_src) { 16712531Swollman register struct vif *vife; 16729209Swollman 16732531Swollman vifp = viftable; 16742531Swollman vife = vifp + numvifs; 16752531Swollman last_encap_src = ip->ip_src.s_addr; 16762531Swollman last_encap_vif = 0; 16772531Swollman for ( ; vifp < vife; ++vifp) 16782531Swollman if (vifp->v_rmt_addr.s_addr == ip->ip_src.s_addr) { 16792531Swollman if ((vifp->v_flags & (VIFF_TUNNEL|VIFF_SRCRT)) 16802531Swollman == VIFF_TUNNEL) 16812531Swollman last_encap_vif = vifp; 16822531Swollman break; 16832531Swollman } 16842531Swollman } 16852531Swollman if ((vifp = last_encap_vif) == 0) { 16862531Swollman last_encap_src = 0; 16872531Swollman mrtstat.mrts_cant_tunnel++; /*XXX*/ 16882531Swollman m_freem(m); 16892531Swollman if (mrtdebug) 169011284Swollman log(LOG_DEBUG, "ip_mforward: no tunnel with %x\n", 16912531Swollman ntohl(ip->ip_src.s_addr)); 16922531Swollman return; 16932531Swollman } 16942531Swollman ifp = vifp->v_ifp; 16957083Swollman 16967083Swollman if (hlen > IP_HDR_LEN) 16977083Swollman ip_stripoptions(m, (struct mbuf *) 0); 16987083Swollman m->m_data += IP_HDR_LEN; 16997083Swollman m->m_len -= IP_HDR_LEN; 17007083Swollman m->m_pkthdr.len -= IP_HDR_LEN; 17017083Swollman m->m_pkthdr.rcvif = ifp; 17027083Swollman 17032531Swollman ifq = &ipintrq; 17042531Swollman s = splimp(); 17052531Swollman if (IF_QFULL(ifq)) { 17062531Swollman IF_DROP(ifq); 17072531Swollman m_freem(m); 17082531Swollman } else { 17092531Swollman IF_ENQUEUE(ifq, m); 17102531Swollman /* 17112531Swollman * normally we would need a "schednetisr(NETISR_IP)" 17122531Swollman * here but we were called by ip_input and it is going 17132531Swollman * to loop back & try to dequeue the packet we just 17142531Swollman * queued as soon as we return so we avoid the 17152531Swollman * unnecessary software interrrupt. 17162531Swollman */ 17172531Swollman } 17182531Swollman splx(s); 17192531Swollman} 17201541Srgrimes 17212531Swollman/* 17222531Swollman * Token bucket filter module 17232531Swollman */ 172410203Swollman 17259209Swollmanstatic void 172610203Swollmantbf_control(vifp, m, ip, p_len) 17272531Swollman register struct vif *vifp; 17281541Srgrimes register struct mbuf *m; 17292531Swollman register struct ip *ip; 17302531Swollman register u_long p_len; 17311541Srgrimes{ 173210203Swollman register struct tbf *t = vifp->v_tbf; 173310203Swollman 173410203Swollman if (p_len > MAX_BKT_SIZE) { 173510203Swollman /* drop if packet is too large */ 173610203Swollman mrtstat.mrts_pkt2large++; 173710203Swollman m_freem(m); 173810203Swollman return; 173910203Swollman } 174010203Swollman 17412531Swollman tbf_update_tokens(vifp); 17421541Srgrimes 17439209Swollman /* if there are enough tokens, 17442531Swollman * and the queue is empty, 17452531Swollman * send this packet out 17462531Swollman */ 17472531Swollman 174810203Swollman if (t->tbf_q_len == 0) { 174910203Swollman /* queue empty, send packet if enough tokens */ 175010203Swollman if (p_len <= t->tbf_n_tok) { 175110203Swollman t->tbf_n_tok -= p_len; 175210203Swollman tbf_send_packet(vifp, m); 17531541Srgrimes } else { 17542531Swollman /* queue packet and timeout till later */ 175510203Swollman tbf_queue(vifp, m); 175610203Swollman timeout(tbf_reprocess_q, (caddr_t)vifp, TBF_REPROCESS); 17572531Swollman } 175810203Swollman } else if (t->tbf_q_len < t->tbf_max_q_len) { 17592531Swollman /* finite queue length, so queue pkts and process queue */ 176010203Swollman tbf_queue(vifp, m); 17612531Swollman tbf_process_q(vifp); 17622531Swollman } else { 17632531Swollman /* queue length too much, try to dq and queue and process */ 17642531Swollman if (!tbf_dq_sel(vifp, ip)) { 17652531Swollman mrtstat.mrts_q_overflow++; 17662531Swollman m_freem(m); 17672531Swollman return; 17682531Swollman } else { 176910203Swollman tbf_queue(vifp, m); 17702531Swollman tbf_process_q(vifp); 17712531Swollman } 17722531Swollman } 17732531Swollman return; 17742531Swollman} 17751541Srgrimes 17769209Swollman/* 17772531Swollman * adds a packet to the queue at the interface 17782531Swollman */ 17799209Swollmanstatic void 178010203Swollmantbf_queue(vifp, m) 17812531Swollman register struct vif *vifp; 17822531Swollman register struct mbuf *m; 17832531Swollman{ 17842531Swollman register int s = splnet(); 178510203Swollman register struct tbf *t = vifp->v_tbf; 17861541Srgrimes 178710203Swollman if (t->tbf_t == NULL) { 178810203Swollman /* Queue was empty */ 178910203Swollman t->tbf_q = m; 179010203Swollman } else { 179110203Swollman /* Insert at tail */ 179210203Swollman t->tbf_t->m_act = m; 179310203Swollman } 17941541Srgrimes 179510203Swollman /* Set new tail pointer */ 179610203Swollman t->tbf_t = m; 17971541Srgrimes 179810203Swollman#ifdef DIAGNOSTIC 179910203Swollman /* Make sure we didn't get fed a bogus mbuf */ 180010203Swollman if (m->m_act) 180110203Swollman panic("tbf_queue: m_act"); 180210203Swollman#endif 180310203Swollman m->m_act = NULL; 180410203Swollman 180510203Swollman t->tbf_q_len++; 180610203Swollman 18072531Swollman splx(s); 18082531Swollman} 18091541Srgrimes 18101541Srgrimes 18119209Swollman/* 18122531Swollman * processes the queue at the interface 18132531Swollman */ 18149209Swollmanstatic void 18152531Swollmantbf_process_q(vifp) 18162531Swollman register struct vif *vifp; 18172531Swollman{ 181810203Swollman register struct mbuf *m; 181910203Swollman register int len; 18202531Swollman register int s = splnet(); 182110203Swollman register struct tbf *t = vifp->v_tbf; 18221541Srgrimes 18232531Swollman /* loop through the queue at the interface and send as many packets 18242531Swollman * as possible 18252531Swollman */ 182610203Swollman while (t->tbf_q_len > 0) { 182710203Swollman m = t->tbf_q; 18282531Swollman 182910203Swollman len = mtod(m, struct ip *)->ip_len; 183010203Swollman 18312531Swollman /* determine if the packet can be sent */ 183210203Swollman if (len <= t->tbf_n_tok) { 18332531Swollman /* if so, 183410203Swollman * reduce no of tokens, dequeue the packet, 18352531Swollman * send the packet. 18362531Swollman */ 183710203Swollman t->tbf_n_tok -= len; 18382531Swollman 183910203Swollman t->tbf_q = m->m_act; 184010203Swollman if (--t->tbf_q_len == 0) 184110203Swollman t->tbf_t = NULL; 18422531Swollman 184310203Swollman m->m_act = NULL; 184410203Swollman tbf_send_packet(vifp, m); 18452531Swollman 18462531Swollman } else break; 18472531Swollman } 18482531Swollman splx(s); 18491541Srgrimes} 18501541Srgrimes 18519209Swollmanstatic void 18522531Swollmantbf_reprocess_q(xvifp) 18532531Swollman void *xvifp; 18541541Srgrimes{ 18552531Swollman register struct vif *vifp = xvifp; 18569209Swollman if (ip_mrouter == NULL) 18572531Swollman return; 18581541Srgrimes 18592531Swollman tbf_update_tokens(vifp); 18601541Srgrimes 18612531Swollman tbf_process_q(vifp); 18622531Swollman 186310203Swollman if (vifp->v_tbf->tbf_q_len) 186410203Swollman timeout(tbf_reprocess_q, (caddr_t)vifp, TBF_REPROCESS); 18652531Swollman} 18662531Swollman 18672531Swollman/* function that will selectively discard a member of the queue 186810203Swollman * based on the precedence value and the priority 18692531Swollman */ 18709209Swollmanstatic int 18712531Swollmantbf_dq_sel(vifp, ip) 18722531Swollman register struct vif *vifp; 18732531Swollman register struct ip *ip; 18742531Swollman{ 18752531Swollman register int s = splnet(); 18762531Swollman register u_int p; 187710203Swollman register struct mbuf *m, *last; 187810203Swollman register struct mbuf **np; 187910203Swollman register struct tbf *t = vifp->v_tbf; 18802531Swollman 18812531Swollman p = priority(vifp, ip); 18822531Swollman 188310203Swollman np = &t->tbf_q; 188410203Swollman last = NULL; 188510203Swollman while ((m = *np) != NULL) { 188610203Swollman if (p > priority(vifp, mtod(m, struct ip *))) { 188710203Swollman *np = m->m_act; 188810203Swollman /* If we're removing the last packet, fix the tail pointer */ 188910203Swollman if (m == t->tbf_t) 189010203Swollman t->tbf_t = last; 189110203Swollman m_freem(m); 189210203Swollman /* it's impossible for the queue to be empty, but 189310203Swollman * we check anyway. */ 189410203Swollman if (--t->tbf_q_len == 0) 189510203Swollman t->tbf_t = NULL; 18962531Swollman splx(s); 18972531Swollman mrtstat.mrts_drop_sel++; 18982531Swollman return(1); 18991541Srgrimes } 190010203Swollman np = &m->m_act; 190110203Swollman last = m; 19022531Swollman } 19032531Swollman splx(s); 19042531Swollman return(0); 19052531Swollman} 19061541Srgrimes 19079209Swollmanstatic void 190810203Swollmantbf_send_packet(vifp, m) 19092531Swollman register struct vif *vifp; 19102531Swollman register struct mbuf *m; 19112531Swollman{ 191210203Swollman struct ip_moptions imo; 19132531Swollman int error; 19142531Swollman int s = splnet(); 19151541Srgrimes 19169209Swollman if (vifp->v_flags & VIFF_TUNNEL) { 19172531Swollman /* If tunnel options */ 19182531Swollman ip_output(m, (struct mbuf *)0, (struct route *)0, 191910203Swollman IP_FORWARDING, (struct ip_moptions *)0); 19202531Swollman } else { 192110203Swollman imo.imo_multicast_ifp = vifp->v_ifp; 192210203Swollman imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1; 192310203Swollman imo.imo_multicast_loop = 1; 192410203Swollman imo.imo_multicast_vif = -1; 192510203Swollman 19262531Swollman error = ip_output(m, (struct mbuf *)0, (struct route *)0, 192710203Swollman IP_FORWARDING, &imo); 19282531Swollman 19299209Swollman if (mrtdebug & DEBUG_XMIT) 193011284Swollman log(LOG_DEBUG, "phyint_send on vif %d err %d\n", 193111284Swollman vifp - viftable, error); 19322531Swollman } 19332531Swollman splx(s); 19341541Srgrimes} 19352531Swollman 19362531Swollman/* determine the current time and then 19372531Swollman * the elapsed time (between the last time and time now) 19382531Swollman * in milliseconds & update the no. of tokens in the bucket 19392531Swollman */ 19409209Swollmanstatic void 19412531Swollmantbf_update_tokens(vifp) 19422531Swollman register struct vif *vifp; 19432531Swollman{ 19442531Swollman struct timeval tp; 194510203Swollman register u_long tm; 19462531Swollman register int s = splnet(); 194710203Swollman register struct tbf *t = vifp->v_tbf; 19482531Swollman 19492531Swollman GET_TIME(tp); 19502531Swollman 195110203Swollman TV_DELTA(tp, t->tbf_last_pkt_t, tm); 19522531Swollman 195310203Swollman /* 195410203Swollman * This formula is actually 195510203Swollman * "time in seconds" * "bytes/second". 195610203Swollman * 195710203Swollman * (tm / 1000000) * (v_rate_limit * 1000 * (1000/1024) / 8) 195810203Swollman * 195910203Swollman * The (1000/1024) was introduced in add_vif to optimize 196010203Swollman * this divide into a shift. 196110203Swollman */ 196210203Swollman t->tbf_n_tok += tm * vifp->v_rate_limit / 1024 / 8; 196310203Swollman t->tbf_last_pkt_t = tp; 19642531Swollman 196510203Swollman if (t->tbf_n_tok > MAX_BKT_SIZE) 196610203Swollman t->tbf_n_tok = MAX_BKT_SIZE; 19672531Swollman 19682531Swollman splx(s); 19692531Swollman} 19702531Swollman 19712531Swollmanstatic int 19722531Swollmanpriority(vifp, ip) 19732531Swollman register struct vif *vifp; 19742531Swollman register struct ip *ip; 19752531Swollman{ 19762531Swollman register int prio; 19772531Swollman 19789209Swollman /* temporary hack; may add general packet classifier some day */ 19792531Swollman 19809209Swollman /* 19819209Swollman * The UDP port space is divided up into four priority ranges: 19829209Swollman * [0, 16384) : unclassified - lowest priority 19839209Swollman * [16384, 32768) : audio - highest priority 19849209Swollman * [32768, 49152) : whiteboard - medium priority 19859209Swollman * [49152, 65536) : video - low priority 19869209Swollman */ 19879209Swollman if (ip->ip_p == IPPROTO_UDP) { 19889209Swollman struct udphdr *udp = (struct udphdr *)(((char *)ip) + (ip->ip_hl << 2)); 19899209Swollman switch (ntohs(udp->uh_dport) & 0xc000) { 19909209Swollman case 0x4000: 19919209Swollman prio = 70; 19929209Swollman break; 19939209Swollman case 0x8000: 19949209Swollman prio = 60; 19959209Swollman break; 19969209Swollman case 0xc000: 19979209Swollman prio = 55; 19989209Swollman break; 19999209Swollman default: 20009209Swollman prio = 50; 20019209Swollman break; 20029209Swollman } 20039209Swollman if (tbfdebug > 1) 200411284Swollman log(LOG_DEBUG, "port %x prio%d\n", ntohs(udp->uh_dport), prio); 20059209Swollman } else { 20069209Swollman prio = 50; 20079209Swollman } 20089209Swollman return prio; 20099209Swollman} 20108876Srgrimes 20119209Swollman/* 20129209Swollman * End of token bucket filter modifications 20139209Swollman */ 20142531Swollman 20159209Swollmanint 20169209Swollmanip_rsvp_vif_init(so, m) 20179209Swollman struct socket *so; 20189209Swollman struct mbuf *m; 20199209Swollman{ 20209209Swollman int i; 20219209Swollman register int s; 20229209Swollman 20239209Swollman if (rsvpdebug) 20249209Swollman printf("ip_rsvp_vif_init: so_type = %d, pr_protocol = %d\n", 20259209Swollman so->so_type, so->so_proto->pr_protocol); 20269209Swollman 20279209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 20289209Swollman return EOPNOTSUPP; 20299209Swollman 20309209Swollman /* Check mbuf. */ 20319209Swollman if (m == NULL || m->m_len != sizeof(int)) { 20329209Swollman return EINVAL; 20332531Swollman } 20349209Swollman i = *(mtod(m, int *)); 20359209Swollman 20369209Swollman if (rsvpdebug) 20379209Swollman printf("ip_rsvp_vif_init: vif = %d rsvp_on = %d\n",i,rsvp_on); 20389209Swollman 20399209Swollman s = splnet(); 20402531Swollman 20419209Swollman /* Check vif. */ 20429209Swollman if (!legal_vif_num(i)) { 20439209Swollman splx(s); 20449209Swollman return EADDRNOTAVAIL; 20459209Swollman } 20462531Swollman 20479209Swollman /* Check if socket is available. */ 20489209Swollman if (viftable[i].v_rsvpd != NULL) { 20499209Swollman splx(s); 20509209Swollman return EADDRINUSE; 20519209Swollman } 20529209Swollman 20539209Swollman viftable[i].v_rsvpd = so; 20549209Swollman /* This may seem silly, but we need to be sure we don't over-increment 20559209Swollman * the RSVP counter, in case something slips up. 20569209Swollman */ 20579209Swollman if (!viftable[i].v_rsvp_on) { 20589209Swollman viftable[i].v_rsvp_on = 1; 20599209Swollman rsvp_on++; 20609209Swollman } 20619209Swollman 20629209Swollman splx(s); 20639209Swollman return 0; 20642531Swollman} 20652531Swollman 20669209Swollmanint 20679209Swollmanip_rsvp_vif_done(so, m) 20689209Swollman struct socket *so; 20699209Swollman struct mbuf *m; 20709209Swollman{ 20719209Swollman int i; 20729209Swollman register int s; 20739209Swollman 20749209Swollman if (rsvpdebug) 20759209Swollman printf("ip_rsvp_vif_done: so_type = %d, pr_protocol = %d\n", 20769209Swollman so->so_type, so->so_proto->pr_protocol); 20779209Swollman 20789209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 20799209Swollman return EOPNOTSUPP; 20809209Swollman 20819209Swollman /* Check mbuf. */ 20829209Swollman if (m == NULL || m->m_len != sizeof(int)) { 20839209Swollman return EINVAL; 20849209Swollman } 20859209Swollman i = *(mtod(m, int *)); 20869209Swollman 20879209Swollman s = splnet(); 20889209Swollman 20899209Swollman /* Check vif. */ 20909209Swollman if (!legal_vif_num(i)) { 20919209Swollman splx(s); 20929209Swollman return EADDRNOTAVAIL; 20939209Swollman } 20942531Swollman 20959209Swollman if (rsvpdebug) 209612296Sphk printf("ip_rsvp_vif_done: v_rsvpd = %p so = %p\n", 20979209Swollman viftable[i].v_rsvpd, so); 20989209Swollman 20999209Swollman viftable[i].v_rsvpd = NULL; 21009209Swollman /* This may seem silly, but we need to be sure we don't over-decrement 21019209Swollman * the RSVP counter, in case something slips up. 21029209Swollman */ 21039209Swollman if (viftable[i].v_rsvp_on) { 21049209Swollman viftable[i].v_rsvp_on = 0; 21059209Swollman rsvp_on--; 21069209Swollman } 21079209Swollman 21089209Swollman splx(s); 21099209Swollman return 0; 21109209Swollman} 21119209Swollman 21129209Swollmanvoid 21139209Swollmanip_rsvp_force_done(so) 21149209Swollman struct socket *so; 21159209Swollman{ 21169209Swollman int vifi; 21179209Swollman register int s; 21189209Swollman 21199209Swollman /* Don't bother if it is not the right type of socket. */ 21209209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 21219209Swollman return; 21229209Swollman 21239209Swollman s = splnet(); 21249209Swollman 21259209Swollman /* The socket may be attached to more than one vif...this 21269209Swollman * is perfectly legal. 21279209Swollman */ 21289209Swollman for (vifi = 0; vifi < numvifs; vifi++) { 21299209Swollman if (viftable[vifi].v_rsvpd == so) { 21309209Swollman viftable[vifi].v_rsvpd = NULL; 21319209Swollman /* This may seem silly, but we need to be sure we don't 21329209Swollman * over-decrement the RSVP counter, in case something slips up. 21339209Swollman */ 21349209Swollman if (viftable[vifi].v_rsvp_on) { 21359209Swollman viftable[vifi].v_rsvp_on = 0; 21369209Swollman rsvp_on--; 21379209Swollman } 21389209Swollman } 21399209Swollman } 21409209Swollman 21419209Swollman splx(s); 21429209Swollman return; 21439209Swollman} 21449209Swollman 21459209Swollmanvoid 21469682Swollmanrsvp_input(m, iphlen) 21479682Swollman struct mbuf *m; 21489682Swollman int iphlen; 21499209Swollman{ 21509209Swollman int vifi; 21519209Swollman register struct ip *ip = mtod(m, struct ip *); 21529682Swollman static struct sockaddr_in rsvp_src = { sizeof rsvp_src, AF_INET }; 21539209Swollman register int s; 21549682Swollman struct ifnet *ifp; 21559209Swollman 21569209Swollman if (rsvpdebug) 21579209Swollman printf("rsvp_input: rsvp_on %d\n",rsvp_on); 21589209Swollman 21599209Swollman /* Can still get packets with rsvp_on = 0 if there is a local member 21609209Swollman * of the group to which the RSVP packet is addressed. But in this 21619209Swollman * case we want to throw the packet away. 21629209Swollman */ 21639209Swollman if (!rsvp_on) { 21649209Swollman m_freem(m); 21659209Swollman return; 21669209Swollman } 21679209Swollman 21689209Swollman /* If the old-style non-vif-associated socket is set, then use 21699209Swollman * it and ignore the new ones. 21709209Swollman */ 21719209Swollman if (ip_rsvpd != NULL) { 21729209Swollman if (rsvpdebug) 21739209Swollman printf("rsvp_input: Sending packet up old-style socket\n"); 21749209Swollman rip_input(m); 21759209Swollman return; 21769209Swollman } 21779209Swollman 21789209Swollman s = splnet(); 21799209Swollman 21809209Swollman if (rsvpdebug) 21819209Swollman printf("rsvp_input: check vifs\n"); 21829209Swollman 21839682Swollman#ifdef DIAGNOSTIC 21849682Swollman if (!(m->m_flags & M_PKTHDR)) 21859682Swollman panic("rsvp_input no hdr"); 21869682Swollman#endif 21879682Swollman 21889682Swollman ifp = m->m_pkthdr.rcvif; 21899209Swollman /* Find which vif the packet arrived on. */ 21909209Swollman for (vifi = 0; vifi < numvifs; vifi++) { 21919209Swollman if (viftable[vifi].v_ifp == ifp) 21929209Swollman break; 21939209Swollman } 21949209Swollman 21959209Swollman if (vifi == numvifs) { 21969209Swollman /* Can't find vif packet arrived on. Drop packet. */ 21979209Swollman if (rsvpdebug) 21989209Swollman printf("rsvp_input: Can't find vif for packet...dropping it.\n"); 21999209Swollman m_freem(m); 22009209Swollman splx(s); 22019209Swollman return; 22029209Swollman } 22039209Swollman 22049209Swollman if (rsvpdebug) 22059209Swollman printf("rsvp_input: check socket\n"); 22069209Swollman 22079209Swollman if (viftable[vifi].v_rsvpd == NULL) { 22089209Swollman /* drop packet, since there is no specific socket for this 22099209Swollman * interface */ 22109209Swollman if (rsvpdebug) 22119209Swollman printf("rsvp_input: No socket defined for vif %d\n",vifi); 22129209Swollman m_freem(m); 22139209Swollman splx(s); 22149209Swollman return; 22159209Swollman } 22169209Swollman rsvp_src.sin_addr = ip->ip_src; 22179209Swollman 22189209Swollman if (rsvpdebug && m) 221912296Sphk printf("rsvp_input: m->m_len = %d, sbspace() = %ld\n", 22209209Swollman m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv))); 22219209Swollman 22229209Swollman if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) 22239209Swollman if (rsvpdebug) 22249209Swollman printf("rsvp_input: Failed to append to socket\n"); 22259209Swollman else 22269209Swollman if (rsvpdebug) 22279209Swollman printf("rsvp_input: send packet up\n"); 22289209Swollman 22299209Swollman splx(s); 22309209Swollman} 22319209Swollman 22322763Swollman#ifdef MROUTE_LKM 22332763Swollman#include <sys/conf.h> 22342763Swollman#include <sys/exec.h> 22352763Swollman#include <sys/sysent.h> 22362763Swollman#include <sys/lkm.h> 22372531Swollman 22382763SwollmanMOD_MISC("ip_mroute_mod") 22392763Swollman 22402763Swollmanstatic int 22412763Swollmanip_mroute_mod_handle(struct lkm_table *lkmtp, int cmd) 22422763Swollman{ 22432763Swollman int i; 22442763Swollman struct lkm_misc *args = lkmtp->private.lkm_misc; 22452763Swollman int err = 0; 22462763Swollman 22472763Swollman switch(cmd) { 22482763Swollman static int (*old_ip_mrouter_cmd)(); 22492763Swollman static int (*old_ip_mrouter_done)(); 22502763Swollman static int (*old_ip_mforward)(); 22512763Swollman static int (*old_mrt_ioctl)(); 22526616Sbde static void (*old_proto4_input)(); 22532763Swollman static int (*old_legal_vif_num)(); 22542763Swollman extern struct protosw inetsw[]; 22552763Swollman 22562763Swollman case LKM_E_LOAD: 22572763Swollman if(lkmexists(lkmtp) || ip_mrtproto) 22582763Swollman return(EEXIST); 22592763Swollman old_ip_mrouter_cmd = ip_mrouter_cmd; 22602763Swollman ip_mrouter_cmd = X_ip_mrouter_cmd; 22612763Swollman old_ip_mrouter_done = ip_mrouter_done; 22622763Swollman ip_mrouter_done = X_ip_mrouter_done; 22632763Swollman old_ip_mforward = ip_mforward; 22642763Swollman ip_mforward = X_ip_mforward; 22652763Swollman old_mrt_ioctl = mrt_ioctl; 22662763Swollman mrt_ioctl = X_mrt_ioctl; 22677083Swollman old_proto4_input = inetsw[ip_protox[ENCAP_PROTO]].pr_input; 22689209Swollman inetsw[ip_protox[ENCAP_PROTO]].pr_input = X_ipip_input; 22692763Swollman old_legal_vif_num = legal_vif_num; 22702763Swollman legal_vif_num = X_legal_vif_num; 22712763Swollman ip_mrtproto = IGMP_DVMRP; 22722763Swollman 22732763Swollman printf("\nIP multicast routing loaded\n"); 22742763Swollman break; 22752763Swollman 22762763Swollman case LKM_E_UNLOAD: 22772763Swollman if (ip_mrouter) 22782763Swollman return EINVAL; 22792763Swollman 22802763Swollman ip_mrouter_cmd = old_ip_mrouter_cmd; 22812763Swollman ip_mrouter_done = old_ip_mrouter_done; 22822763Swollman ip_mforward = old_ip_mforward; 22832763Swollman mrt_ioctl = old_mrt_ioctl; 22847083Swollman inetsw[ip_protox[ENCAP_PROTO]].pr_input = old_proto4_input; 22852763Swollman legal_vif_num = old_legal_vif_num; 22862763Swollman ip_mrtproto = 0; 22872763Swollman break; 22882763Swollman 22892763Swollman default: 22902763Swollman err = EINVAL; 22912763Swollman break; 22922763Swollman } 22932763Swollman 22942763Swollman return(err); 22952763Swollman} 22962763Swollman 22972763Swollmanint 22982763Swollmanip_mroute_mod(struct lkm_table *lkmtp, int cmd, int ver) { 22992763Swollman DISPATCH(lkmtp, cmd, ver, ip_mroute_mod_handle, ip_mroute_mod_handle, 23002763Swollman nosys); 23012763Swollman} 23022763Swollman 23032763Swollman#endif /* MROUTE_LKM */ 23042763Swollman#endif /* MROUTING */ 2305