ip_mroute.c revision 14546
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 1214546Sdg * $Id: ip_mroute.c,v 1.28 1996/03/02 18:24:10 peter 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{ 11109209Swollman register struct mfc *rt = 0; /* XXX uninit warning */ 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 } 11519209Swollman return (ip_mdq(m, ifp, rt, 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; 11929209Swollman#ifdef UPCALL_TIMING 11939209Swollman struct timeval tp; 11942531Swollman 11959209Swollman GET_TIME(tp); 11969209Swollman#endif 11979209Swollman 11982531Swollman mrtstat.mrts_no_route++; 11999209Swollman if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC)) 120011284Swollman log(LOG_DEBUG, "ip_mforward: no rte s %x g %x\n", 12012531Swollman ntohl(ip->ip_src.s_addr), 12022531Swollman ntohl(ip->ip_dst.s_addr)); 12032531Swollman 12049209Swollman /* 12059209Swollman * Allocate mbufs early so that we don't do extra work if we are 12069209Swollman * just going to fail anyway. 12079209Swollman */ 12089209Swollman MGET(mb_ntry, M_DONTWAIT, MT_DATA); 12099209Swollman if (mb_ntry == NULL) { 12109209Swollman splx(s); 12119209Swollman return ENOBUFS; 12129209Swollman } 12139209Swollman mb0 = m_copy(m, 0, M_COPYALL); 12149209Swollman if (mb0 == NULL) { 12159209Swollman m_free(mb_ntry); 12169209Swollman splx(s); 12179209Swollman return ENOBUFS; 12189209Swollman } 12199209Swollman 12202531Swollman /* is there an upcall waiting for this packet? */ 12219209Swollman hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr); 12222531Swollman for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) { 12232531Swollman rt = mtod(mb_rt, struct mfc *); 12249209Swollman if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) && 12252531Swollman (ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) && 12262531Swollman (mb_rt->m_act != NULL)) 12272531Swollman break; 12282531Swollman } 12292531Swollman 12302531Swollman if (mb_rt == NULL) { 12319209Swollman int hlen = ip->ip_hl << 2; 12329209Swollman int i; 12339209Swollman struct igmpmsg *im; 12349209Swollman 12352531Swollman /* no upcall, so make a new entry */ 12362531Swollman MGET(mb_rt, M_DONTWAIT, MT_MRTABLE); 12372531Swollman if (mb_rt == NULL) { 12389209Swollman m_free(mb_ntry); 12399266Swollman m_freem(mb0); 12402531Swollman splx(s); 12412531Swollman return ENOBUFS; 12422531Swollman } 12439209Swollman /* Make a copy of the header to send to the user level process */ 12449209Swollman mm = m_copy(m, 0, hlen); 12459209Swollman if (mm && (M_HASCL(mm) || mm->m_len < hlen)) 12469209Swollman mm = m_pullup(mm, hlen); 12479209Swollman if (mm == NULL) { 12489209Swollman m_free(mb_ntry); 12499266Swollman m_freem(mb0); 12509209Swollman m_free(mb_rt); 12519209Swollman splx(s); 12529209Swollman return ENOBUFS; 12539209Swollman } 12542531Swollman 12559209Swollman /* 12569209Swollman * Send message to routing daemon to install 12579209Swollman * a route into the kernel table 12589209Swollman */ 12599209Swollman k_igmpsrc.sin_addr = ip->ip_src; 12609209Swollman 12619209Swollman im = mtod(mm, struct igmpmsg *); 12629209Swollman im->im_msgtype = IGMPMSG_NOCACHE; 12639209Swollman im->im_mbz = 0; 12649209Swollman 12659209Swollman mrtstat.mrts_upcalls++; 12669209Swollman 12679209Swollman if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) { 126811284Swollman log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n"); 12699209Swollman ++mrtstat.mrts_upq_sockfull; 12709209Swollman m_free(mb_ntry); 12719266Swollman m_freem(mb0); 12729209Swollman m_free(mb_rt); 12739209Swollman splx(s); 12749209Swollman return ENOBUFS; 12759209Swollman } 12769209Swollman 12772531Swollman rt = mtod(mb_rt, struct mfc *); 12782531Swollman 12792531Swollman /* insert new entry at head of hash chain */ 12802531Swollman rt->mfc_origin.s_addr = ip->ip_src.s_addr; 12812531Swollman rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr; 12829209Swollman rt->mfc_expire = UPCALL_EXPIRE; 12839209Swollman nexpire[hash]++; 12849209Swollman for (i = 0; i < numvifs; i++) 12859209Swollman rt->mfc_ttls[i] = 0; 12869209Swollman rt->mfc_parent = -1; 12872531Swollman 12882531Swollman /* link into table */ 12892531Swollman mb_rt->m_next = mfctable[hash]; 12902531Swollman mfctable[hash] = mb_rt; 12912531Swollman mb_rt->m_act = NULL; 12922531Swollman 12939209Swollman rte_m = mb_rt; 12949209Swollman } else { 12959209Swollman /* determine if q has overflowed */ 12969209Swollman for (rte_m = mb_rt, npkts = 0; rte_m->m_act; rte_m = rte_m->m_act) 12979209Swollman npkts++; 12982531Swollman 12999209Swollman if (npkts > MAX_UPQ) { 13009209Swollman mrtstat.mrts_upq_ovflw++; 13019209Swollman m_free(mb_ntry); 13029266Swollman m_freem(mb0); 13039209Swollman splx(s); 13049209Swollman return 0; 13059209Swollman } 13062531Swollman } 13072531Swollman 13082531Swollman mb_ntry->m_act = NULL; 13092531Swollman rte = mtod(mb_ntry, struct rtdetq *); 13102531Swollman 13112531Swollman rte->m = mb0; 13122531Swollman rte->ifp = ifp; 13139209Swollman#ifdef UPCALL_TIMING 13149209Swollman rte->t = tp; 13159209Swollman#endif 13162531Swollman 13179209Swollman /* Add this entry to the end of the queue */ 13189209Swollman rte_m->m_act = mb_ntry; 13192531Swollman 13202531Swollman splx(s); 13212531Swollman 13222531Swollman return 0; 13239209Swollman } 13241541Srgrimes} 13251541Srgrimes 13262763Swollman#ifndef MROUTE_LKM 13272754Swollmanint (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, 13282763Swollman struct ip_moptions *) = X_ip_mforward; 13292763Swollman#endif 13302754Swollman 13311541Srgrimes/* 13322531Swollman * Clean up the cache entry if upcall is not serviced 13331541Srgrimes */ 13342531Swollmanstatic void 13359209Swollmanexpire_upcalls(void *unused) 13361541Srgrimes{ 13379209Swollman struct mbuf *mb_rt, *m, **nptr; 13382531Swollman struct rtdetq *rte; 13399209Swollman struct mfc *mfc; 13409209Swollman int i; 13412531Swollman int s; 13421541Srgrimes 13432531Swollman s = splnet(); 13449209Swollman for (i = 0; i < MFCTBLSIZ; i++) { 13459209Swollman if (nexpire[i] == 0) 13469209Swollman continue; 13479209Swollman nptr = &mfctable[i]; 13489209Swollman for (mb_rt = *nptr; mb_rt != NULL; mb_rt = *nptr) { 13499209Swollman mfc = mtod(mb_rt, struct mfc *); 13502531Swollman 13519209Swollman /* 13529209Swollman * Skip real cache entries 13539209Swollman * Make sure it wasn't marked to not expire (shouldn't happen) 13549209Swollman * If it expires now 13559209Swollman */ 13569209Swollman if (mb_rt->m_act != NULL && 13579209Swollman mfc->mfc_expire != 0 && 13589209Swollman --mfc->mfc_expire == 0) { 13599209Swollman if (mrtdebug & DEBUG_EXPIRE) 136011284Swollman log(LOG_DEBUG, "expire_upcalls: expiring (%x %x)\n", 13619209Swollman ntohl(mfc->mfc_origin.s_addr), 13629209Swollman ntohl(mfc->mfc_mcastgrp.s_addr)); 13639209Swollman /* 13649209Swollman * drop all the packets 13659209Swollman * free the mbuf with the pkt, if, timing info 13669209Swollman */ 13679209Swollman while (mb_rt->m_act) { 13689209Swollman m = mb_rt->m_act; 13699209Swollman mb_rt->m_act = m->m_act; 13709209Swollman 13719209Swollman rte = mtod(m, struct rtdetq *); 13729209Swollman m_freem(rte->m); 13739209Swollman m_free(m); 13749209Swollman } 13759209Swollman ++mrtstat.mrts_cache_cleanups; 13769209Swollman nexpire[i]--; 13772531Swollman 13789209Swollman MFREE(mb_rt, *nptr); 13799209Swollman } else { 13809209Swollman nptr = &mb_rt->m_next; 13819209Swollman } 13829209Swollman } 13832531Swollman } 13842531Swollman splx(s); 13859209Swollman timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); 13861541Srgrimes} 13871541Srgrimes 13881541Srgrimes/* 13892531Swollman * Packet forwarding routine once entry in the cache is made 13901541Srgrimes */ 13911541Srgrimesstatic int 13929209Swollmanip_mdq(m, ifp, rt, xmt_vif) 13932531Swollman register struct mbuf *m; 13942531Swollman register struct ifnet *ifp; 13952531Swollman register struct mfc *rt; 13969209Swollman register vifi_t xmt_vif; 13971541Srgrimes{ 13982531Swollman register struct ip *ip = mtod(m, struct ip *); 13992531Swollman register vifi_t vifi; 14002531Swollman register struct vif *vifp; 14019209Swollman register int plen = ntohs(ip->ip_len); 14021541Srgrimes 14039209Swollman/* 14049209Swollman * Macro to send packet on vif. Since RSVP packets don't get counted on 14059209Swollman * input, they shouldn't get counted on output, so statistics keeping is 14069209Swollman * seperate. 14079209Swollman */ 14089209Swollman#define MC_SEND(ip,vifp,m) { \ 14099209Swollman if ((vifp)->v_flags & VIFF_TUNNEL) \ 14109209Swollman encap_send((ip), (vifp), (m)); \ 14119209Swollman else \ 14129209Swollman phyint_send((ip), (vifp), (m)); \ 14139209Swollman} 14149209Swollman 14152531Swollman /* 14169209Swollman * If xmt_vif is not -1, send on only the requested vif. 14179209Swollman * 14189209Swollman * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.) 14199209Swollman */ 14209209Swollman if (xmt_vif < numvifs) { 14219209Swollman MC_SEND(ip, viftable + xmt_vif, m); 14229209Swollman return 1; 14239209Swollman } 14249209Swollman 14259209Swollman /* 14262531Swollman * Don't forward if it didn't arrive from the parent vif for its origin. 14272531Swollman */ 14282531Swollman vifi = rt->mfc_parent; 14299209Swollman if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) { 14302531Swollman /* came in the wrong interface */ 14319209Swollman if (mrtdebug & DEBUG_FORWARD) 143211284Swollman log(LOG_DEBUG, "wrong if: ifp %x vifi %d vififp %x\n", 14339209Swollman ifp, vifi, viftable[vifi].v_ifp); 14342531Swollman ++mrtstat.mrts_wrong_if; 14359209Swollman ++rt->mfc_wrong_if; 14369209Swollman /* 14379209Swollman * If we are doing PIM assert processing, and we are forwarding 14389209Swollman * packets on this interface, and it is a broadcast medium 14399209Swollman * interface (and not a tunnel), send a message to the routing daemon. 14409209Swollman */ 14419209Swollman if (pim_assert && rt->mfc_ttls[vifi] && 14429209Swollman (ifp->if_flags & IFF_BROADCAST) && 14439209Swollman !(viftable[vifi].v_flags & VIFF_TUNNEL)) { 14449209Swollman struct sockaddr_in k_igmpsrc; 14459209Swollman struct mbuf *mm; 14469209Swollman struct igmpmsg *im; 14479209Swollman int hlen = ip->ip_hl << 2; 14489209Swollman struct timeval now; 14499209Swollman register u_long delta; 14509209Swollman 14519209Swollman GET_TIME(now); 14529209Swollman 14539209Swollman TV_DELTA(rt->mfc_last_assert, now, delta); 14549209Swollman 14559209Swollman if (delta > ASSERT_MSG_TIME) { 14569209Swollman mm = m_copy(m, 0, hlen); 14579209Swollman if (mm && (M_HASCL(mm) || mm->m_len < hlen)) 14589209Swollman mm = m_pullup(mm, hlen); 14599209Swollman if (mm == NULL) { 14609209Swollman return ENOBUFS; 14619209Swollman } 14629209Swollman 14639209Swollman rt->mfc_last_assert = now; 14649209Swollman 14659209Swollman im = mtod(mm, struct igmpmsg *); 14669209Swollman im->im_msgtype = IGMPMSG_WRONGVIF; 14679209Swollman im->im_mbz = 0; 14689209Swollman im->im_vif = vifi; 14699209Swollman 14709209Swollman k_igmpsrc.sin_addr = im->im_src; 14719209Swollman 14729334Swollman socket_send(ip_mrouter, mm, &k_igmpsrc); 14739209Swollman } 14749209Swollman } 14759209Swollman return 0; 14762531Swollman } 14771541Srgrimes 14789209Swollman /* If I sourced this packet, it counts as output, else it was input. */ 14799209Swollman if (ip->ip_src.s_addr == viftable[vifi].v_lcl_addr.s_addr) { 14809209Swollman viftable[vifi].v_pkt_out++; 14819209Swollman viftable[vifi].v_bytes_out += plen; 14829209Swollman } else { 14839209Swollman viftable[vifi].v_pkt_in++; 14849209Swollman viftable[vifi].v_bytes_in += plen; 14859209Swollman } 14862531Swollman rt->mfc_pkt_cnt++; 14879209Swollman rt->mfc_byte_cnt += plen; 14881541Srgrimes 14892531Swollman /* 14902531Swollman * For each vif, decide if a copy of the packet should be forwarded. 14912531Swollman * Forward if: 14922531Swollman * - the ttl exceeds the vif's threshold 14932531Swollman * - there are group members downstream on interface 14942531Swollman */ 14952531Swollman for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) 14962531Swollman if ((rt->mfc_ttls[vifi] > 0) && 14979209Swollman (ip->ip_ttl > rt->mfc_ttls[vifi])) { 14989209Swollman vifp->v_pkt_out++; 14999209Swollman vifp->v_bytes_out += plen; 15002531Swollman MC_SEND(ip, vifp, m); 15019209Swollman } 15022531Swollman 15032531Swollman return 0; 15041541Srgrimes} 15051541Srgrimes 15069209Swollman/* 15079209Swollman * check if a vif number is legal/ok. This is used by ip_output, to export 15089209Swollman * numvifs there, 15091541Srgrimes */ 151012296Sphkstatic int 15112763SwollmanX_legal_vif_num(vif) 15122531Swollman int vif; 15139209Swollman{ 15149209Swollman if (vif >= 0 && vif < numvifs) 15152531Swollman return(1); 15162531Swollman else 15172531Swollman return(0); 15182531Swollman} 15192531Swollman 15202763Swollman#ifndef MROUTE_LKM 15212763Swollmanint (*legal_vif_num)(int) = X_legal_vif_num; 15222763Swollman#endif 15232754Swollman 15249209Swollman/* 15259209Swollman * Return the local address used by this vif 15269209Swollman */ 152712296Sphkstatic u_long 15289209SwollmanX_ip_mcast_src(vifi) 15299209Swollman int vifi; 15309209Swollman{ 15319209Swollman if (vifi >= 0 && vifi < numvifs) 15329209Swollman return viftable[vifi].v_lcl_addr.s_addr; 15339209Swollman else 15349209Swollman return INADDR_ANY; 15359209Swollman} 15369209Swollman 15379209Swollman#ifndef MROUTE_LKM 15389209Swollmanu_long (*ip_mcast_src)(int) = X_ip_mcast_src; 15399209Swollman#endif 15409209Swollman 15412531Swollmanstatic void 15422531Swollmanphyint_send(ip, vifp, m) 15432531Swollman struct ip *ip; 15442531Swollman struct vif *vifp; 15452531Swollman struct mbuf *m; 15461541Srgrimes{ 15472531Swollman register struct mbuf *mb_copy; 15489209Swollman register int hlen = ip->ip_hl << 2; 15491541Srgrimes 15503571Swollman /* 15519209Swollman * Make a new reference to the packet; make sure that 15529209Swollman * the IP header is actually copied, not just referenced, 15539209Swollman * so that ip_output() only scribbles on the copy. 15543571Swollman */ 15559209Swollman mb_copy = m_copy(m, 0, M_COPYALL); 15569209Swollman if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < hlen)) 15579209Swollman mb_copy = m_pullup(mb_copy, hlen); 15583571Swollman if (mb_copy == NULL) 15599209Swollman return; 15603571Swollman 15612531Swollman if (vifp->v_rate_limit <= 0) 156210203Swollman tbf_send_packet(vifp, mb_copy); 15632531Swollman else 156410203Swollman tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *), ip->ip_len); 15652531Swollman} 15661541Srgrimes 15672531Swollmanstatic void 15682531Swollmanencap_send(ip, vifp, m) 15692531Swollman register struct ip *ip; 15702531Swollman register struct vif *vifp; 15712531Swollman register struct mbuf *m; 15721541Srgrimes{ 15732531Swollman register struct mbuf *mb_copy; 15742531Swollman register struct ip *ip_copy; 15752531Swollman register int i, len = ip->ip_len; 15761541Srgrimes 15772531Swollman /* 15782531Swollman * copy the old packet & pullup it's IP header into the 15792531Swollman * new mbuf so we can modify it. Try to fill the new 15802531Swollman * mbuf since if we don't the ethernet driver will. 15812531Swollman */ 15822531Swollman MGET(mb_copy, M_DONTWAIT, MT_DATA); 15832531Swollman if (mb_copy == NULL) 15842531Swollman return; 15852531Swollman mb_copy->m_data += 16; 15862531Swollman mb_copy->m_len = sizeof(multicast_encap_iphdr); 15871541Srgrimes 15882531Swollman if ((mb_copy->m_next = m_copy(m, 0, M_COPYALL)) == NULL) { 15892531Swollman m_freem(mb_copy); 15902531Swollman return; 15912531Swollman } 15922531Swollman i = MHLEN - M_LEADINGSPACE(mb_copy); 15932531Swollman if (i > len) 15942531Swollman i = len; 15952531Swollman mb_copy = m_pullup(mb_copy, i); 15962531Swollman if (mb_copy == NULL) 15972531Swollman return; 15983571Swollman mb_copy->m_pkthdr.len = len + sizeof(multicast_encap_iphdr); 15991541Srgrimes 16002531Swollman /* 16012531Swollman * fill in the encapsulating IP header. 16022531Swollman */ 16032531Swollman ip_copy = mtod(mb_copy, struct ip *); 16042531Swollman *ip_copy = multicast_encap_iphdr; 16052531Swollman ip_copy->ip_id = htons(ip_id++); 16062531Swollman ip_copy->ip_len += len; 16072531Swollman ip_copy->ip_src = vifp->v_lcl_addr; 16082531Swollman ip_copy->ip_dst = vifp->v_rmt_addr; 16091541Srgrimes 16102531Swollman /* 16112531Swollman * turn the encapsulated IP header back into a valid one. 16122531Swollman */ 16132531Swollman ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr)); 16142531Swollman --ip->ip_ttl; 16152531Swollman HTONS(ip->ip_len); 16162531Swollman HTONS(ip->ip_off); 16172531Swollman ip->ip_sum = 0; 16182531Swollman#if defined(LBL) && !defined(ultrix) 16192531Swollman ip->ip_sum = ~oc_cksum((caddr_t)ip, ip->ip_hl << 2, 0); 16202531Swollman#else 16212531Swollman mb_copy->m_data += sizeof(multicast_encap_iphdr); 16222531Swollman ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2); 16232531Swollman mb_copy->m_data -= sizeof(multicast_encap_iphdr); 16242531Swollman#endif 16252531Swollman 16262531Swollman if (vifp->v_rate_limit <= 0) 162710203Swollman tbf_send_packet(vifp, mb_copy); 16282531Swollman else 162910203Swollman tbf_control(vifp, mb_copy, ip, ip_copy->ip_len); 16301541Srgrimes} 16311541Srgrimes 16321541Srgrimes/* 16332531Swollman * De-encapsulate a packet and feed it back through ip input (this 16342531Swollman * routine is called whenever IP gets a packet with proto type 16352531Swollman * ENCAP_PROTO and a local destination address). 16361541Srgrimes */ 16372531Swollmanvoid 16382763Swollman#ifdef MROUTE_LKM 16399209SwollmanX_ipip_input(m) 16402763Swollman#else 16419209Swollmanipip_input(m, iphlen) 16422763Swollman#endif 16439209Swollman register struct mbuf *m; 16449209Swollman int iphlen; 16452531Swollman{ 16462531Swollman struct ifnet *ifp = m->m_pkthdr.rcvif; 16472531Swollman register struct ip *ip = mtod(m, struct ip *); 16482531Swollman register int hlen = ip->ip_hl << 2; 16492531Swollman register int s; 16502531Swollman register struct ifqueue *ifq; 16512531Swollman register struct vif *vifp; 16521541Srgrimes 16539209Swollman if (!have_encap_tunnel) { 16549209Swollman rip_input(m); 16559209Swollman return; 16562531Swollman } 16572531Swollman /* 16582531Swollman * dump the packet if it's not to a multicast destination or if 16592531Swollman * we don't have an encapsulating tunnel with the source. 16602531Swollman * Note: This code assumes that the remote site IP address 16612531Swollman * uniquely identifies the tunnel (i.e., that this site has 16622531Swollman * at most one tunnel with the remote site). 16632531Swollman */ 16642531Swollman if (! IN_MULTICAST(ntohl(((struct ip *)((char *)ip + hlen))->ip_dst.s_addr))) { 16652531Swollman ++mrtstat.mrts_bad_tunnel; 16662531Swollman m_freem(m); 16672531Swollman return; 16682531Swollman } 16692531Swollman if (ip->ip_src.s_addr != last_encap_src) { 16702531Swollman register struct vif *vife; 16719209Swollman 16722531Swollman vifp = viftable; 16732531Swollman vife = vifp + numvifs; 16742531Swollman last_encap_src = ip->ip_src.s_addr; 16752531Swollman last_encap_vif = 0; 16762531Swollman for ( ; vifp < vife; ++vifp) 16772531Swollman if (vifp->v_rmt_addr.s_addr == ip->ip_src.s_addr) { 16782531Swollman if ((vifp->v_flags & (VIFF_TUNNEL|VIFF_SRCRT)) 16792531Swollman == VIFF_TUNNEL) 16802531Swollman last_encap_vif = vifp; 16812531Swollman break; 16822531Swollman } 16832531Swollman } 16842531Swollman if ((vifp = last_encap_vif) == 0) { 16852531Swollman last_encap_src = 0; 16862531Swollman mrtstat.mrts_cant_tunnel++; /*XXX*/ 16872531Swollman m_freem(m); 16882531Swollman if (mrtdebug) 168911284Swollman log(LOG_DEBUG, "ip_mforward: no tunnel with %x\n", 16902531Swollman ntohl(ip->ip_src.s_addr)); 16912531Swollman return; 16922531Swollman } 16932531Swollman ifp = vifp->v_ifp; 16947083Swollman 16957083Swollman if (hlen > IP_HDR_LEN) 16967083Swollman ip_stripoptions(m, (struct mbuf *) 0); 16977083Swollman m->m_data += IP_HDR_LEN; 16987083Swollman m->m_len -= IP_HDR_LEN; 16997083Swollman m->m_pkthdr.len -= IP_HDR_LEN; 17007083Swollman m->m_pkthdr.rcvif = ifp; 17017083Swollman 17022531Swollman ifq = &ipintrq; 17032531Swollman s = splimp(); 17042531Swollman if (IF_QFULL(ifq)) { 17052531Swollman IF_DROP(ifq); 17062531Swollman m_freem(m); 17072531Swollman } else { 17082531Swollman IF_ENQUEUE(ifq, m); 17092531Swollman /* 17102531Swollman * normally we would need a "schednetisr(NETISR_IP)" 17112531Swollman * here but we were called by ip_input and it is going 17122531Swollman * to loop back & try to dequeue the packet we just 17132531Swollman * queued as soon as we return so we avoid the 17142531Swollman * unnecessary software interrrupt. 17152531Swollman */ 17162531Swollman } 17172531Swollman splx(s); 17182531Swollman} 17191541Srgrimes 17202531Swollman/* 17212531Swollman * Token bucket filter module 17222531Swollman */ 172310203Swollman 17249209Swollmanstatic void 172510203Swollmantbf_control(vifp, m, ip, p_len) 17262531Swollman register struct vif *vifp; 17271541Srgrimes register struct mbuf *m; 17282531Swollman register struct ip *ip; 17292531Swollman register u_long p_len; 17301541Srgrimes{ 173110203Swollman register struct tbf *t = vifp->v_tbf; 173210203Swollman 173310203Swollman if (p_len > MAX_BKT_SIZE) { 173410203Swollman /* drop if packet is too large */ 173510203Swollman mrtstat.mrts_pkt2large++; 173610203Swollman m_freem(m); 173710203Swollman return; 173810203Swollman } 173910203Swollman 17402531Swollman tbf_update_tokens(vifp); 17411541Srgrimes 17429209Swollman /* if there are enough tokens, 17432531Swollman * and the queue is empty, 17442531Swollman * send this packet out 17452531Swollman */ 17462531Swollman 174710203Swollman if (t->tbf_q_len == 0) { 174810203Swollman /* queue empty, send packet if enough tokens */ 174910203Swollman if (p_len <= t->tbf_n_tok) { 175010203Swollman t->tbf_n_tok -= p_len; 175110203Swollman tbf_send_packet(vifp, m); 17521541Srgrimes } else { 17532531Swollman /* queue packet and timeout till later */ 175410203Swollman tbf_queue(vifp, m); 175510203Swollman timeout(tbf_reprocess_q, (caddr_t)vifp, TBF_REPROCESS); 17562531Swollman } 175710203Swollman } else if (t->tbf_q_len < t->tbf_max_q_len) { 17582531Swollman /* finite queue length, so queue pkts and process queue */ 175910203Swollman tbf_queue(vifp, m); 17602531Swollman tbf_process_q(vifp); 17612531Swollman } else { 17622531Swollman /* queue length too much, try to dq and queue and process */ 17632531Swollman if (!tbf_dq_sel(vifp, ip)) { 17642531Swollman mrtstat.mrts_q_overflow++; 17652531Swollman m_freem(m); 17662531Swollman return; 17672531Swollman } else { 176810203Swollman tbf_queue(vifp, m); 17692531Swollman tbf_process_q(vifp); 17702531Swollman } 17712531Swollman } 17722531Swollman return; 17732531Swollman} 17741541Srgrimes 17759209Swollman/* 17762531Swollman * adds a packet to the queue at the interface 17772531Swollman */ 17789209Swollmanstatic void 177910203Swollmantbf_queue(vifp, m) 17802531Swollman register struct vif *vifp; 17812531Swollman register struct mbuf *m; 17822531Swollman{ 17832531Swollman register int s = splnet(); 178410203Swollman register struct tbf *t = vifp->v_tbf; 17851541Srgrimes 178610203Swollman if (t->tbf_t == NULL) { 178710203Swollman /* Queue was empty */ 178810203Swollman t->tbf_q = m; 178910203Swollman } else { 179010203Swollman /* Insert at tail */ 179110203Swollman t->tbf_t->m_act = m; 179210203Swollman } 17931541Srgrimes 179410203Swollman /* Set new tail pointer */ 179510203Swollman t->tbf_t = m; 17961541Srgrimes 179710203Swollman#ifdef DIAGNOSTIC 179810203Swollman /* Make sure we didn't get fed a bogus mbuf */ 179910203Swollman if (m->m_act) 180010203Swollman panic("tbf_queue: m_act"); 180110203Swollman#endif 180210203Swollman m->m_act = NULL; 180310203Swollman 180410203Swollman t->tbf_q_len++; 180510203Swollman 18062531Swollman splx(s); 18072531Swollman} 18081541Srgrimes 18091541Srgrimes 18109209Swollman/* 18112531Swollman * processes the queue at the interface 18122531Swollman */ 18139209Swollmanstatic void 18142531Swollmantbf_process_q(vifp) 18152531Swollman register struct vif *vifp; 18162531Swollman{ 181710203Swollman register struct mbuf *m; 181810203Swollman register int len; 18192531Swollman register int s = splnet(); 182010203Swollman register struct tbf *t = vifp->v_tbf; 18211541Srgrimes 18222531Swollman /* loop through the queue at the interface and send as many packets 18232531Swollman * as possible 18242531Swollman */ 182510203Swollman while (t->tbf_q_len > 0) { 182610203Swollman m = t->tbf_q; 18272531Swollman 182810203Swollman len = mtod(m, struct ip *)->ip_len; 182910203Swollman 18302531Swollman /* determine if the packet can be sent */ 183110203Swollman if (len <= t->tbf_n_tok) { 18322531Swollman /* if so, 183310203Swollman * reduce no of tokens, dequeue the packet, 18342531Swollman * send the packet. 18352531Swollman */ 183610203Swollman t->tbf_n_tok -= len; 18372531Swollman 183810203Swollman t->tbf_q = m->m_act; 183910203Swollman if (--t->tbf_q_len == 0) 184010203Swollman t->tbf_t = NULL; 18412531Swollman 184210203Swollman m->m_act = NULL; 184310203Swollman tbf_send_packet(vifp, m); 18442531Swollman 18452531Swollman } else break; 18462531Swollman } 18472531Swollman splx(s); 18481541Srgrimes} 18491541Srgrimes 18509209Swollmanstatic void 18512531Swollmantbf_reprocess_q(xvifp) 18522531Swollman void *xvifp; 18531541Srgrimes{ 18542531Swollman register struct vif *vifp = xvifp; 18559209Swollman if (ip_mrouter == NULL) 18562531Swollman return; 18571541Srgrimes 18582531Swollman tbf_update_tokens(vifp); 18591541Srgrimes 18602531Swollman tbf_process_q(vifp); 18612531Swollman 186210203Swollman if (vifp->v_tbf->tbf_q_len) 186310203Swollman timeout(tbf_reprocess_q, (caddr_t)vifp, TBF_REPROCESS); 18642531Swollman} 18652531Swollman 18662531Swollman/* function that will selectively discard a member of the queue 186710203Swollman * based on the precedence value and the priority 18682531Swollman */ 18699209Swollmanstatic int 18702531Swollmantbf_dq_sel(vifp, ip) 18712531Swollman register struct vif *vifp; 18722531Swollman register struct ip *ip; 18732531Swollman{ 18742531Swollman register int s = splnet(); 18752531Swollman register u_int p; 187610203Swollman register struct mbuf *m, *last; 187710203Swollman register struct mbuf **np; 187810203Swollman register struct tbf *t = vifp->v_tbf; 18792531Swollman 18802531Swollman p = priority(vifp, ip); 18812531Swollman 188210203Swollman np = &t->tbf_q; 188310203Swollman last = NULL; 188410203Swollman while ((m = *np) != NULL) { 188510203Swollman if (p > priority(vifp, mtod(m, struct ip *))) { 188610203Swollman *np = m->m_act; 188710203Swollman /* If we're removing the last packet, fix the tail pointer */ 188810203Swollman if (m == t->tbf_t) 188910203Swollman t->tbf_t = last; 189010203Swollman m_freem(m); 189110203Swollman /* it's impossible for the queue to be empty, but 189210203Swollman * we check anyway. */ 189310203Swollman if (--t->tbf_q_len == 0) 189410203Swollman t->tbf_t = NULL; 18952531Swollman splx(s); 18962531Swollman mrtstat.mrts_drop_sel++; 18972531Swollman return(1); 18981541Srgrimes } 189910203Swollman np = &m->m_act; 190010203Swollman last = m; 19012531Swollman } 19022531Swollman splx(s); 19032531Swollman return(0); 19042531Swollman} 19051541Srgrimes 19069209Swollmanstatic void 190710203Swollmantbf_send_packet(vifp, m) 19082531Swollman register struct vif *vifp; 19092531Swollman register struct mbuf *m; 19102531Swollman{ 191110203Swollman struct ip_moptions imo; 19122531Swollman int error; 19132531Swollman int s = splnet(); 19141541Srgrimes 19159209Swollman if (vifp->v_flags & VIFF_TUNNEL) { 19162531Swollman /* If tunnel options */ 19172531Swollman ip_output(m, (struct mbuf *)0, (struct route *)0, 191810203Swollman IP_FORWARDING, (struct ip_moptions *)0); 19192531Swollman } else { 192010203Swollman imo.imo_multicast_ifp = vifp->v_ifp; 192110203Swollman imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1; 192210203Swollman imo.imo_multicast_loop = 1; 192310203Swollman imo.imo_multicast_vif = -1; 192410203Swollman 19252531Swollman error = ip_output(m, (struct mbuf *)0, (struct route *)0, 192610203Swollman IP_FORWARDING, &imo); 19272531Swollman 19289209Swollman if (mrtdebug & DEBUG_XMIT) 192911284Swollman log(LOG_DEBUG, "phyint_send on vif %d err %d\n", 193011284Swollman vifp - viftable, error); 19312531Swollman } 19322531Swollman splx(s); 19331541Srgrimes} 19342531Swollman 19352531Swollman/* determine the current time and then 19362531Swollman * the elapsed time (between the last time and time now) 19372531Swollman * in milliseconds & update the no. of tokens in the bucket 19382531Swollman */ 19399209Swollmanstatic void 19402531Swollmantbf_update_tokens(vifp) 19412531Swollman register struct vif *vifp; 19422531Swollman{ 19432531Swollman struct timeval tp; 194410203Swollman register u_long tm; 19452531Swollman register int s = splnet(); 194610203Swollman register struct tbf *t = vifp->v_tbf; 19472531Swollman 19482531Swollman GET_TIME(tp); 19492531Swollman 195010203Swollman TV_DELTA(tp, t->tbf_last_pkt_t, tm); 19512531Swollman 195210203Swollman /* 195310203Swollman * This formula is actually 195410203Swollman * "time in seconds" * "bytes/second". 195510203Swollman * 195610203Swollman * (tm / 1000000) * (v_rate_limit * 1000 * (1000/1024) / 8) 195710203Swollman * 195810203Swollman * The (1000/1024) was introduced in add_vif to optimize 195910203Swollman * this divide into a shift. 196010203Swollman */ 196110203Swollman t->tbf_n_tok += tm * vifp->v_rate_limit / 1024 / 8; 196210203Swollman t->tbf_last_pkt_t = tp; 19632531Swollman 196410203Swollman if (t->tbf_n_tok > MAX_BKT_SIZE) 196510203Swollman t->tbf_n_tok = MAX_BKT_SIZE; 19662531Swollman 19672531Swollman splx(s); 19682531Swollman} 19692531Swollman 19702531Swollmanstatic int 19712531Swollmanpriority(vifp, ip) 19722531Swollman register struct vif *vifp; 19732531Swollman register struct ip *ip; 19742531Swollman{ 19752531Swollman register int prio; 19762531Swollman 19779209Swollman /* temporary hack; may add general packet classifier some day */ 19782531Swollman 19799209Swollman /* 19809209Swollman * The UDP port space is divided up into four priority ranges: 19819209Swollman * [0, 16384) : unclassified - lowest priority 19829209Swollman * [16384, 32768) : audio - highest priority 19839209Swollman * [32768, 49152) : whiteboard - medium priority 19849209Swollman * [49152, 65536) : video - low priority 19859209Swollman */ 19869209Swollman if (ip->ip_p == IPPROTO_UDP) { 19879209Swollman struct udphdr *udp = (struct udphdr *)(((char *)ip) + (ip->ip_hl << 2)); 19889209Swollman switch (ntohs(udp->uh_dport) & 0xc000) { 19899209Swollman case 0x4000: 19909209Swollman prio = 70; 19919209Swollman break; 19929209Swollman case 0x8000: 19939209Swollman prio = 60; 19949209Swollman break; 19959209Swollman case 0xc000: 19969209Swollman prio = 55; 19979209Swollman break; 19989209Swollman default: 19999209Swollman prio = 50; 20009209Swollman break; 20019209Swollman } 20029209Swollman if (tbfdebug > 1) 200311284Swollman log(LOG_DEBUG, "port %x prio%d\n", ntohs(udp->uh_dport), prio); 20049209Swollman } else { 20059209Swollman prio = 50; 20069209Swollman } 20079209Swollman return prio; 20089209Swollman} 20098876Srgrimes 20109209Swollman/* 20119209Swollman * End of token bucket filter modifications 20129209Swollman */ 20132531Swollman 20149209Swollmanint 20159209Swollmanip_rsvp_vif_init(so, m) 20169209Swollman struct socket *so; 20179209Swollman struct mbuf *m; 20189209Swollman{ 20199209Swollman int i; 20209209Swollman register int s; 20219209Swollman 20229209Swollman if (rsvpdebug) 20239209Swollman printf("ip_rsvp_vif_init: so_type = %d, pr_protocol = %d\n", 20249209Swollman so->so_type, so->so_proto->pr_protocol); 20259209Swollman 20269209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 20279209Swollman return EOPNOTSUPP; 20289209Swollman 20299209Swollman /* Check mbuf. */ 20309209Swollman if (m == NULL || m->m_len != sizeof(int)) { 20319209Swollman return EINVAL; 20322531Swollman } 20339209Swollman i = *(mtod(m, int *)); 20349209Swollman 20359209Swollman if (rsvpdebug) 20369209Swollman printf("ip_rsvp_vif_init: vif = %d rsvp_on = %d\n",i,rsvp_on); 20379209Swollman 20389209Swollman s = splnet(); 20392531Swollman 20409209Swollman /* Check vif. */ 20419209Swollman if (!legal_vif_num(i)) { 20429209Swollman splx(s); 20439209Swollman return EADDRNOTAVAIL; 20449209Swollman } 20452531Swollman 20469209Swollman /* Check if socket is available. */ 20479209Swollman if (viftable[i].v_rsvpd != NULL) { 20489209Swollman splx(s); 20499209Swollman return EADDRINUSE; 20509209Swollman } 20519209Swollman 20529209Swollman viftable[i].v_rsvpd = so; 20539209Swollman /* This may seem silly, but we need to be sure we don't over-increment 20549209Swollman * the RSVP counter, in case something slips up. 20559209Swollman */ 20569209Swollman if (!viftable[i].v_rsvp_on) { 20579209Swollman viftable[i].v_rsvp_on = 1; 20589209Swollman rsvp_on++; 20599209Swollman } 20609209Swollman 20619209Swollman splx(s); 20629209Swollman return 0; 20632531Swollman} 20642531Swollman 20659209Swollmanint 20669209Swollmanip_rsvp_vif_done(so, m) 20679209Swollman struct socket *so; 20689209Swollman struct mbuf *m; 20699209Swollman{ 20709209Swollman int i; 20719209Swollman register int s; 20729209Swollman 20739209Swollman if (rsvpdebug) 20749209Swollman printf("ip_rsvp_vif_done: so_type = %d, pr_protocol = %d\n", 20759209Swollman so->so_type, so->so_proto->pr_protocol); 20769209Swollman 20779209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 20789209Swollman return EOPNOTSUPP; 20799209Swollman 20809209Swollman /* Check mbuf. */ 20819209Swollman if (m == NULL || m->m_len != sizeof(int)) { 20829209Swollman return EINVAL; 20839209Swollman } 20849209Swollman i = *(mtod(m, int *)); 20859209Swollman 20869209Swollman s = splnet(); 20879209Swollman 20889209Swollman /* Check vif. */ 20899209Swollman if (!legal_vif_num(i)) { 20909209Swollman splx(s); 20919209Swollman return EADDRNOTAVAIL; 20929209Swollman } 20932531Swollman 20949209Swollman if (rsvpdebug) 209512296Sphk printf("ip_rsvp_vif_done: v_rsvpd = %p so = %p\n", 20969209Swollman viftable[i].v_rsvpd, so); 20979209Swollman 20989209Swollman viftable[i].v_rsvpd = NULL; 20999209Swollman /* This may seem silly, but we need to be sure we don't over-decrement 21009209Swollman * the RSVP counter, in case something slips up. 21019209Swollman */ 21029209Swollman if (viftable[i].v_rsvp_on) { 21039209Swollman viftable[i].v_rsvp_on = 0; 21049209Swollman rsvp_on--; 21059209Swollman } 21069209Swollman 21079209Swollman splx(s); 21089209Swollman return 0; 21099209Swollman} 21109209Swollman 21119209Swollmanvoid 21129209Swollmanip_rsvp_force_done(so) 21139209Swollman struct socket *so; 21149209Swollman{ 21159209Swollman int vifi; 21169209Swollman register int s; 21179209Swollman 21189209Swollman /* Don't bother if it is not the right type of socket. */ 21199209Swollman if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) 21209209Swollman return; 21219209Swollman 21229209Swollman s = splnet(); 21239209Swollman 21249209Swollman /* The socket may be attached to more than one vif...this 21259209Swollman * is perfectly legal. 21269209Swollman */ 21279209Swollman for (vifi = 0; vifi < numvifs; vifi++) { 21289209Swollman if (viftable[vifi].v_rsvpd == so) { 21299209Swollman viftable[vifi].v_rsvpd = NULL; 21309209Swollman /* This may seem silly, but we need to be sure we don't 21319209Swollman * over-decrement the RSVP counter, in case something slips up. 21329209Swollman */ 21339209Swollman if (viftable[vifi].v_rsvp_on) { 21349209Swollman viftable[vifi].v_rsvp_on = 0; 21359209Swollman rsvp_on--; 21369209Swollman } 21379209Swollman } 21389209Swollman } 21399209Swollman 21409209Swollman splx(s); 21419209Swollman return; 21429209Swollman} 21439209Swollman 21449209Swollmanvoid 21459682Swollmanrsvp_input(m, iphlen) 21469682Swollman struct mbuf *m; 21479682Swollman int iphlen; 21489209Swollman{ 21499209Swollman int vifi; 21509209Swollman register struct ip *ip = mtod(m, struct ip *); 21519682Swollman static struct sockaddr_in rsvp_src = { sizeof rsvp_src, AF_INET }; 21529209Swollman register int s; 21539682Swollman struct ifnet *ifp; 21549209Swollman 21559209Swollman if (rsvpdebug) 21569209Swollman printf("rsvp_input: rsvp_on %d\n",rsvp_on); 21579209Swollman 21589209Swollman /* Can still get packets with rsvp_on = 0 if there is a local member 21599209Swollman * of the group to which the RSVP packet is addressed. But in this 21609209Swollman * case we want to throw the packet away. 21619209Swollman */ 21629209Swollman if (!rsvp_on) { 21639209Swollman m_freem(m); 21649209Swollman return; 21659209Swollman } 21669209Swollman 21679209Swollman /* If the old-style non-vif-associated socket is set, then use 21689209Swollman * it and ignore the new ones. 21699209Swollman */ 21709209Swollman if (ip_rsvpd != NULL) { 21719209Swollman if (rsvpdebug) 21729209Swollman printf("rsvp_input: Sending packet up old-style socket\n"); 21739209Swollman rip_input(m); 21749209Swollman return; 21759209Swollman } 21769209Swollman 21779209Swollman s = splnet(); 21789209Swollman 21799209Swollman if (rsvpdebug) 21809209Swollman printf("rsvp_input: check vifs\n"); 21819209Swollman 21829682Swollman#ifdef DIAGNOSTIC 21839682Swollman if (!(m->m_flags & M_PKTHDR)) 21849682Swollman panic("rsvp_input no hdr"); 21859682Swollman#endif 21869682Swollman 21879682Swollman ifp = m->m_pkthdr.rcvif; 21889209Swollman /* Find which vif the packet arrived on. */ 21899209Swollman for (vifi = 0; vifi < numvifs; vifi++) { 21909209Swollman if (viftable[vifi].v_ifp == ifp) 21919209Swollman break; 21929209Swollman } 21939209Swollman 21949209Swollman if (vifi == numvifs) { 21959209Swollman /* Can't find vif packet arrived on. Drop packet. */ 21969209Swollman if (rsvpdebug) 21979209Swollman printf("rsvp_input: Can't find vif for packet...dropping it.\n"); 21989209Swollman m_freem(m); 21999209Swollman splx(s); 22009209Swollman return; 22019209Swollman } 22029209Swollman 22039209Swollman if (rsvpdebug) 22049209Swollman printf("rsvp_input: check socket\n"); 22059209Swollman 22069209Swollman if (viftable[vifi].v_rsvpd == NULL) { 22079209Swollman /* drop packet, since there is no specific socket for this 22089209Swollman * interface */ 22099209Swollman if (rsvpdebug) 22109209Swollman printf("rsvp_input: No socket defined for vif %d\n",vifi); 22119209Swollman m_freem(m); 22129209Swollman splx(s); 22139209Swollman return; 22149209Swollman } 22159209Swollman rsvp_src.sin_addr = ip->ip_src; 22169209Swollman 22179209Swollman if (rsvpdebug && m) 221812296Sphk printf("rsvp_input: m->m_len = %d, sbspace() = %ld\n", 22199209Swollman m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv))); 22209209Swollman 22219209Swollman if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) 22229209Swollman if (rsvpdebug) 22239209Swollman printf("rsvp_input: Failed to append to socket\n"); 22249209Swollman else 22259209Swollman if (rsvpdebug) 22269209Swollman printf("rsvp_input: send packet up\n"); 22279209Swollman 22289209Swollman splx(s); 22299209Swollman} 22309209Swollman 22312763Swollman#ifdef MROUTE_LKM 22322763Swollman#include <sys/conf.h> 22332763Swollman#include <sys/exec.h> 22342763Swollman#include <sys/sysent.h> 22352763Swollman#include <sys/lkm.h> 22362531Swollman 22372763SwollmanMOD_MISC("ip_mroute_mod") 22382763Swollman 22392763Swollmanstatic int 22402763Swollmanip_mroute_mod_handle(struct lkm_table *lkmtp, int cmd) 22412763Swollman{ 22422763Swollman int i; 22432763Swollman struct lkm_misc *args = lkmtp->private.lkm_misc; 22442763Swollman int err = 0; 22452763Swollman 22462763Swollman switch(cmd) { 22472763Swollman static int (*old_ip_mrouter_cmd)(); 22482763Swollman static int (*old_ip_mrouter_done)(); 22492763Swollman static int (*old_ip_mforward)(); 22502763Swollman static int (*old_mrt_ioctl)(); 22516616Sbde static void (*old_proto4_input)(); 22522763Swollman static int (*old_legal_vif_num)(); 22532763Swollman extern struct protosw inetsw[]; 22542763Swollman 22552763Swollman case LKM_E_LOAD: 22562763Swollman if(lkmexists(lkmtp) || ip_mrtproto) 22572763Swollman return(EEXIST); 22582763Swollman old_ip_mrouter_cmd = ip_mrouter_cmd; 22592763Swollman ip_mrouter_cmd = X_ip_mrouter_cmd; 22602763Swollman old_ip_mrouter_done = ip_mrouter_done; 22612763Swollman ip_mrouter_done = X_ip_mrouter_done; 22622763Swollman old_ip_mforward = ip_mforward; 22632763Swollman ip_mforward = X_ip_mforward; 22642763Swollman old_mrt_ioctl = mrt_ioctl; 22652763Swollman mrt_ioctl = X_mrt_ioctl; 22667083Swollman old_proto4_input = inetsw[ip_protox[ENCAP_PROTO]].pr_input; 22679209Swollman inetsw[ip_protox[ENCAP_PROTO]].pr_input = X_ipip_input; 22682763Swollman old_legal_vif_num = legal_vif_num; 22692763Swollman legal_vif_num = X_legal_vif_num; 22702763Swollman ip_mrtproto = IGMP_DVMRP; 22712763Swollman 22722763Swollman printf("\nIP multicast routing loaded\n"); 22732763Swollman break; 22742763Swollman 22752763Swollman case LKM_E_UNLOAD: 22762763Swollman if (ip_mrouter) 22772763Swollman return EINVAL; 22782763Swollman 22792763Swollman ip_mrouter_cmd = old_ip_mrouter_cmd; 22802763Swollman ip_mrouter_done = old_ip_mrouter_done; 22812763Swollman ip_mforward = old_ip_mforward; 22822763Swollman mrt_ioctl = old_mrt_ioctl; 22837083Swollman inetsw[ip_protox[ENCAP_PROTO]].pr_input = old_proto4_input; 22842763Swollman legal_vif_num = old_legal_vif_num; 22852763Swollman ip_mrtproto = 0; 22862763Swollman break; 22872763Swollman 22882763Swollman default: 22892763Swollman err = EINVAL; 22902763Swollman break; 22912763Swollman } 22922763Swollman 22932763Swollman return(err); 22942763Swollman} 22952763Swollman 22962763Swollmanint 22972763Swollmanip_mroute_mod(struct lkm_table *lkmtp, int cmd, int ver) { 22982763Swollman DISPATCH(lkmtp, cmd, ver, ip_mroute_mod_handle, ip_mroute_mod_handle, 22992763Swollman nosys); 23002763Swollman} 23012763Swollman 23022763Swollman#endif /* MROUTE_LKM */ 23032763Swollman#endif /* MROUTING */ 2304