summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1995-06-13 17:51:16 +0000
committerwollman <wollman@FreeBSD.org>1995-06-13 17:51:16 +0000
commit20ad4f8359820cf12331c0335034438fc23ad604 (patch)
treeb5de17b0bb0d03b7ed728b104d3d0f4a9752fd4a /sys
parentc0dfcf234735c518d2c756c46fddf87d2332c838 (diff)
downloadFreeBSD-src-20ad4f8359820cf12331c0335034438fc23ad604.zip
FreeBSD-src-20ad4f8359820cf12331c0335034438fc23ad604.tar.gz
Kernel side of 3.5 multicast routing code, based on work by Bill Fenner
and other work done here. The LKM support is probably broken, but it still compiles and will be fixed later.
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/igmp.c193
-rw-r--r--sys/netinet/igmp.h57
-rw-r--r--sys/netinet/igmp_var.h22
-rw-r--r--sys/netinet/in.h8
-rw-r--r--sys/netinet/in_proto.c9
-rw-r--r--sys/netinet/ip_input.c34
-rw-r--r--sys/netinet/ip_mroute.c1646
-rw-r--r--sys/netinet/ip_mroute.h135
-rw-r--r--sys/netinet/ip_output.c25
-rw-r--r--sys/netinet/ip_var.h7
-rw-r--r--sys/netinet/raw_ip.c51
11 files changed, 1276 insertions, 911 deletions
diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c
index dac0add..cd0a35e 100644
--- a/sys/netinet/igmp.c
+++ b/sys/netinet/igmp.c
@@ -43,8 +43,9 @@
*
* Written by Steve Deering, Stanford, May 1988.
* Modified by Rosen Sharma, Stanford, Aug 1994.
+ * Modified by Bill Fenner, Xerox PARC, Feb 1995.
*
- * MULTICAST 1.4
+ * MULTICAST Revision: 3.3.1.2
*/
#include <sys/param.h>
@@ -69,9 +70,11 @@
struct igmpstat igmpstat;
-static int igmp_timers_are_running = 0;
+static int igmp_timers_are_running;
static u_long igmp_all_hosts_group;
-static struct router_info *Head = 0;
+static u_long igmp_local_group;
+static u_long igmp_local_group_mask;
+static struct router_info *Head;
static void igmp_sendpkt(struct in_multi *, int);
static void igmp_sendleave(struct in_multi *);
@@ -83,6 +86,11 @@ igmp_init()
* To avoid byte-swapping the same value over and over again.
*/
igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP);
+ igmp_local_group = htonl(0xe0000000); /* 224.0.0.0 */
+ igmp_local_group_mask = htonl(0xffffff00); /* ........^ */
+
+ igmp_timers_are_running = 0;
+
Head = (struct router_info *) 0;
}
@@ -96,13 +104,12 @@ fill_rti(inm)
printf("[igmp.c, _fill_rti] --> entering \n");
#endif
while (rti) {
- if (rti->ifp == inm->inm_ifp){ /* ? is it ok to compare */
- /* pointers */
+ if (rti->ifp == inm->inm_ifp) {
inm->inm_rti = rti;
#ifdef IGMP_DEBUG
printf("[igmp.c, _fill_rti] --> found old entry \n");
#endif
- if (rti->type == IGMP_OLD_ROUTER)
+ if (rti->type == IGMP_OLD_ROUTER)
return IGMP_HOST_MEMBERSHIP_REPORT;
else
return IGMP_HOST_NEW_MEMBERSHIP_REPORT;
@@ -114,7 +121,7 @@ fill_rti(inm)
rti->type = IGMP_NEW_ROUTER;
rti->time = IGMP_AGE_THRESHOLD;
rti->next = Head;
- Head = rti;
+ Head = rti;
inm->inm_rti = rti;
#ifdef IGMP_DEBUG
printf("[igmp.c, _fill_rti] --> created new entry \n");
@@ -132,7 +139,7 @@ find_rti(ifp)
printf("[igmp.c, _find_rti] --> entering \n");
#endif
while (rti) {
- if (rti->ifp == ifp){ /* ? is it ok to compare pointers */
+ if (rti->ifp == ifp) {
#ifdef IGMP_DEBUG
printf("[igmp.c, _find_rti] --> found old entry \n");
#endif
@@ -166,7 +173,7 @@ igmp_input(m, iphlen)
register struct in_ifaddr *ia;
struct in_multistep step;
struct router_info *rti;
-
+
int timer; /** timer value in the igmp query header **/
++igmpstat.igps_rcv_total;
@@ -232,15 +239,16 @@ igmp_input(m, iphlen)
/*
* Start the timers in all of our membership records for
* the interface on which the query arrived, except those
- * that are already running and those that belong to the
- * "all-hosts" group.
+ * that are already running and those that belong to a
+ * "local" group (224.0.0.X).
*/
IN_FIRST_MULTI(step, inm);
while (inm != NULL) {
- if (inm->inm_ifp == ifp
+ if (inm->inm_ifp == ifp
&& inm->inm_timer == 0
- && inm->inm_addr.s_addr
- != igmp_all_hosts_group) {
+ && ((inm->inm_addr.s_addr
+ & igmp_local_group_mask)
+ != igmp_local_group)) {
inm->inm_state = IGMP_DELAYING_MEMBER;
inm->inm_timer = IGMP_RANDOM_DELAY(
@@ -254,44 +262,40 @@ igmp_input(m, iphlen)
/*
** New Router
*/
-
- if (ip->ip_dst.s_addr != igmp_all_hosts_group) {
- if (!(m->m_flags & M_MCAST)) {
- ++igmpstat.igps_rcv_badqueries;
- m_freem(m);
- return;
- }
+
+ if (!(m->m_flags & M_MCAST)) {
+ ++igmpstat.igps_rcv_badqueries;
+ m_freem(m);
+ return;
}
- if (ip->ip_dst.s_addr == igmp_all_hosts_group) {
-
- /*
- * - Start the timers in all of our membership records
- * for the interface on which the query arrived
- * excl. those that belong to the "all-hosts" group.
- * - For timers already running check if they need to
- * be reset.
- * - Use the igmp->igmp_code filed as the maximum
- * delay possible
- */
- IN_FIRST_MULTI(step, inm);
- while (inm != NULL){
- switch(inm->inm_state){
+
+ /*
+ * - Start the timers in all of our membership records
+ * that the query applies to for the interface on
+ * which the query arrived excl. those that belong
+ * to a "local" group (224.0.0.X)
+ * - For timers already running check if they need to
+ * be reset.
+ * - Use the igmp->igmp_code field as the maximum
+ * delay possible
+ */
+ IN_FIRST_MULTI(step, inm);
+ while (inm != NULL) {
+ if (inm->inm_ifp == ifp &&
+ (inm->inm_addr.s_addr & igmp_local_group_mask) !=
+ igmp_local_group &&
+ (ip->ip_dst.s_addr == igmp_all_hosts_group ||
+ ip->ip_dst.s_addr == inm->inm_addr.s_addr)) {
+ switch(inm->inm_state) {
case IGMP_IDLE_MEMBER:
case IGMP_LAZY_MEMBER:
case IGMP_AWAKENING_MEMBER:
- if (inm->inm_ifp == ifp &&
- inm->inm_addr.s_addr !=
- igmp_all_hosts_group) {
inm->inm_timer = IGMP_RANDOM_DELAY(timer);
igmp_timers_are_running = 1;
inm->inm_state = IGMP_DELAYING_MEMBER;
- }
- break;
+ break;
case IGMP_DELAYING_MEMBER:
- if (inm->inm_ifp == ifp &&
- (inm->inm_timer > timer) &&
- inm->inm_addr.s_addr !=
- igmp_all_hosts_group) {
+ if (inm->inm_timer > timer) {
inm->inm_timer = IGMP_RANDOM_DELAY(timer);
igmp_timers_are_running = 1;
inm->inm_state = IGMP_DELAYING_MEMBER;
@@ -301,48 +305,17 @@ igmp_input(m, iphlen)
inm->inm_state = IGMP_AWAKENING_MEMBER;
break;
}
- IN_NEXT_MULTI(step, inm);
- }
- } else {
- /*
- ** group specific query
- */
-
- IN_FIRST_MULTI(step, inm);
- while (inm != NULL) {
- if (inm->inm_addr.s_addr == ip->ip_dst.s_addr) {
- switch(inm->inm_state ){
- case IGMP_IDLE_MEMBER:
- case IGMP_LAZY_MEMBER:
- case IGMP_AWAKENING_MEMBER:
- inm->inm_state = IGMP_DELAYING_MEMBER;
- if (inm->inm_ifp == ifp ) {
- inm->inm_timer = IGMP_RANDOM_DELAY(timer);
- igmp_timers_are_running = 1;
- inm->inm_state = IGMP_DELAYING_MEMBER;
- }
- break;
- case IGMP_DELAYING_MEMBER:
- inm->inm_state = IGMP_DELAYING_MEMBER;
- if (inm->inm_ifp == ifp &&
- (inm->inm_timer > timer) ) {
- inm->inm_timer = IGMP_RANDOM_DELAY(timer);
- igmp_timers_are_running = 1;
- inm->inm_state = IGMP_DELAYING_MEMBER;
- }
- break;
- case IGMP_SLEEPING_MEMBER:
- inm->inm_state = IGMP_AWAKENING_MEMBER;
- break;
- }
}
IN_NEXT_MULTI(step, inm);
}
- }
}
+
break;
case IGMP_HOST_MEMBERSHIP_REPORT:
+ /*
+ * an old report
+ */
++igmpstat.igps_rcv_reports;
if (ifp->if_flags & IFF_LOOPBACK)
@@ -374,15 +347,11 @@ igmp_input(m, iphlen)
* our timer for that group.
*/
IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
- if (inm != NULL) {
- inm->inm_timer = 0;
- ++igmpstat.igps_rcv_ourreports;
- }
if (inm != NULL) {
inm->inm_timer = 0;
++igmpstat.igps_rcv_ourreports;
-
+
switch(inm->inm_state){
case IGMP_IDLE_MEMBER:
case IGMP_LAZY_MEMBER:
@@ -391,32 +360,43 @@ igmp_input(m, iphlen)
inm->inm_state = IGMP_SLEEPING_MEMBER;
break;
case IGMP_DELAYING_MEMBER:
- /** check this out - this was if (oldrouter) **/
if (inm->inm_rti->type == IGMP_OLD_ROUTER)
inm->inm_state = IGMP_LAZY_MEMBER;
- else inm->inm_state = IGMP_SLEEPING_MEMBER;
+ else
+ inm->inm_state = IGMP_SLEEPING_MEMBER;
break;
}
}
-
+
break;
case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
/*
- * an new report
+ * a new report
*/
- ++igmpstat.igps_rcv_reports;
+ /*
+ * We can get confused and think there's someone
+ * else out there if we are a multicast router.
+ * For fast leave to work, we have to know that
+ * we are the only member.
+ */
+ IFP_TO_IA(ifp, ia);
+ if (ia && ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr)
+ break;
+
+ ++igmpstat.igps_rcv_reports;
+
if (ifp->if_flags & IFF_LOOPBACK)
break;
-
+
if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
++igmpstat.igps_rcv_badreports;
m_freem(m);
return;
}
-
+
/*
* KLUDGE: if the IP source address of the report has an
* unspecified (i.e., zero) subnet number, as is allowed for
@@ -427,10 +407,12 @@ igmp_input(m, iphlen)
* determine the arrival interface of an incoming packet.
*/
if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) {
+/* #ifndef MROUTING XXX - I don't think the ifdef is necessary */
IFP_TO_IA(ifp, ia);
+/* #endif */
if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet);
}
-
+
/*
* If we belong to the group being reported, stop
* our timer for that group.
@@ -439,7 +421,7 @@ igmp_input(m, iphlen)
if (inm != NULL) {
inm->inm_timer = 0;
++igmpstat.igps_rcv_ourreports;
-
+
switch(inm->inm_state){
case IGMP_DELAYING_MEMBER:
case IGMP_IDLE_MEMBER:
@@ -466,12 +448,12 @@ void
igmp_joingroup(inm)
struct in_multi *inm;
{
- register int s = splnet();
+ int s = splnet();
inm->inm_state = IGMP_IDLE_MEMBER;
- if (inm->inm_addr.s_addr == igmp_all_hosts_group ||
- inm->inm_ifp->if_flags & IFF_LOOPBACK)
+ if ((inm->inm_addr.s_addr & igmp_local_group_mask) == igmp_local_group
+ || inm->inm_ifp->if_flags & IFF_LOOPBACK)
inm->inm_timer = 0;
else {
igmp_sendpkt(inm,fill_rti(inm));
@@ -487,14 +469,12 @@ void
igmp_leavegroup(inm)
struct in_multi *inm;
{
- /*
- * No action required on leaving a group.
- */
- switch(inm->inm_state){
+ switch(inm->inm_state) {
case IGMP_DELAYING_MEMBER:
case IGMP_IDLE_MEMBER:
- if (!(inm->inm_addr.s_addr == igmp_all_hosts_group ||
- inm->inm_ifp->if_flags & IFF_LOOPBACK))
+ if (((inm->inm_addr.s_addr & igmp_local_group_mask)
+ != igmp_local_group)
+ && !(inm->inm_ifp->if_flags & IFF_LOOPBACK))
if (inm->inm_rti->type != IGMP_OLD_ROUTER)
igmp_sendleave(inm);
break;
@@ -509,13 +489,14 @@ void
igmp_fasttimo()
{
register struct in_multi *inm;
- register int s;
struct in_multistep step;
+ int s;
/*
* Quick check to see if any work needs to be done, in order
* to minimize the overhead of fasttimo processing.
*/
+
if (!igmp_timers_are_running)
return;
@@ -558,7 +539,7 @@ igmp_slowtimo()
}
rti = rti->next;
}
-#ifdef IGMP_DEBUG
+#ifdef IGMP_DEBUG
printf("[igmp.c,_slowtimo] -- > exiting \n");
#endif
splx(s);
@@ -608,6 +589,7 @@ igmp_sendpkt(inm, type)
imo->imo_multicast_ifp = inm->inm_ifp;
imo->imo_multicast_ttl = 1;
+ imo->imo_multicast_vif = -1;
/*
* Request loopback of the report if we are acting as a multicast
* router, so that the process-level routing demon can hear it.
@@ -618,7 +600,6 @@ igmp_sendpkt(inm, type)
FREE(imo, M_IPMOPTS);
++igmpstat.igps_snd_reports;
-
}
static void
@@ -638,7 +619,7 @@ igmp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
switch(name[0]) {
case IGMPCTL_STATS:
- return sysctl_rdstruct(oldp, oldlenp, newp, &igmpstat,
+ return sysctl_rdstruct(oldp, oldlenp, newp, &igmpstat,
sizeof igmpstat);
default:
return ENOPROTOOPT;
diff --git a/sys/netinet/igmp.h b/sys/netinet/igmp.h
index 4011b4c..a7038f3 100644
--- a/sys/netinet/igmp.h
+++ b/sys/netinet/igmp.h
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* @(#)igmp.h 8.1 (Berkeley) 6/10/93
- * $Id: igmp.h,v 1.4 1994/09/06 22:42:17 wollman Exp $
+ * $Id: igmp.h,v 1.4 1994/09/06 22:42:17 wollman Exp $
*/
#ifndef _NETINET_IGMP_H_
@@ -46,7 +46,7 @@
*
* Written by Steve Deering, Stanford, May 1988.
*
- * MULTICAST 1.2
+ * MULTICAST Revision: 3.3.1.2
*/
/*
@@ -54,40 +54,53 @@
*/
struct igmp {
u_char igmp_type; /* version & type of IGMP message */
- u_char igmp_code; /* unused, should be zero */
+ u_char igmp_code; /* subtype for routing msgs */
u_short igmp_cksum; /* IP-style checksum */
struct in_addr igmp_group; /* group address being reported */
}; /* (zero for queries) */
#define IGMP_MINLEN 8
-#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* message types, incl. version */
-#define IGMP_HOST_MEMBERSHIP_REPORT 0x12
-#define IGMP_DVMRP 0x13 /* for experimental multicast */
- /* routing protocol */
-#define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16
-#define IGMP_HOST_LEAVE_MESSAGE 0x17
-#define IGMP_MTRACE 0x1f /* mcast traceroute messages */
-#define IGMP_MTRACE_RESP 0x1e /* traceroute resp. (to sender) */
+/*
+ * Message types, including version number.
+ */
+#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* Host membership query */
+#define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Old membership report */
+#define IGMP_DVMRP 0x13 /* DVMRP routing message */
+#define IGMP_PIM 0x14 /* PIM routing message */
+
+#define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16 /* New membership report */
+
+#define IGMP_HOST_LEAVE_MESSAGE 0x17 /* Leave-group message */
+
+#define IGMP_MTRACE_RESP 0x1e /* traceroute resp. (to sender) */
+#define IGMP_MTRACE 0x1f /* mcast traceroute messages */
+
+#define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */
+ /* query (in seconds) */
-#define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */
#define IGMP_TIMER_SCALE 10 /* denotes that the igmp->timer filed */
- /*specifies time in 10th os seconds */
+ /*specifies time in tenths of seconds */
+/*
+ * States for the IGMPv2 state table
+ */
#define IGMP_DELAYING_MEMBER 1
#define IGMP_IDLE_MEMBER 2
-#define IGMP_LAZY_MEMBER 3
-#define IGMP_SLEEPING_MEMBER 4
-#define IGMP_AWAKENING_MEMBER 5
-
+#define IGMP_LAZY_MEMBER 3
+#define IGMP_SLEEPING_MEMBER 4
+#define IGMP_AWAKENING_MEMBER 5
+/*
+ * We must remember whether the querier is an old or a new router.
+ */
#define IGMP_OLD_ROUTER 0
#define IGMP_NEW_ROUTER 1
-#define IGMP_AGE_THRESHOLD 540
+/*
+ * Revert to new router if we haven't heard from an old router in
+ * this amount of time.
+ */
+#define IGMP_AGE_THRESHOLD 540
-#ifdef IGMP_STATES
-static char *tostate[]={"","DELAYING_MEMBER","IDLE","LAZY","SLEEPING",
- "AWAKENING" };
-#endif /* IGMP_STATES */
#endif /* _NETINET_IGMP_H_ */
diff --git a/sys/netinet/igmp_var.h b/sys/netinet/igmp_var.h
index 0de226c..1c013c7 100644
--- a/sys/netinet/igmp_var.h
+++ b/sys/netinet/igmp_var.h
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* @(#)igmp_var.h 8.1 (Berkeley) 7/19/93
- * $Id: igmp_var.h,v 1.4 1994/09/06 22:42:17 wollman Exp $
+ * $Id: igmp_var.h,v 1.5 1995/02/16 00:27:42 wollman Exp $
*/
#ifndef _NETINET_IGMP_VAR_H_
@@ -47,19 +47,19 @@
*
* Written by Steve Deering, Stanford, May 1988.
*
- * MULTICAST 1.1
+ * MULTICAST Revisiob: 3.3.1.1
*/
struct igmpstat {
- u_long igps_rcv_total; /* total IGMP messages received */
- u_long igps_rcv_tooshort; /* received with too few bytes */
- u_long igps_rcv_badsum; /* received with bad checksum */
- u_long igps_rcv_queries; /* received membership queries */
- u_long igps_rcv_badqueries; /* received invalid queries */
- u_long igps_rcv_reports; /* received membership reports */
- u_long igps_rcv_badreports; /* received invalid reports */
- u_long igps_rcv_ourreports; /* received reports for our groups */
- u_long igps_snd_reports; /* sent membership reports */
+ u_int igps_rcv_total; /* total IGMP messages received */
+ u_int igps_rcv_tooshort; /* received with too few bytes */
+ u_int igps_rcv_badsum; /* received with bad checksum */
+ u_int igps_rcv_queries; /* received membership queries */
+ u_int igps_rcv_badqueries; /* received invalid queries */
+ u_int igps_rcv_reports; /* received membership reports */
+ u_int igps_rcv_badreports; /* received invalid reports */
+ u_int igps_rcv_ourreports; /* received reports for our groups */
+ u_int igps_snd_reports; /* sent membership reports */
};
#ifdef KERNEL
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index b9f8b1d..80c5b2b 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)in.h 8.3 (Berkeley) 1/3/94
- * $Id: in.h,v 1.7 1995/02/14 23:04:50 wollman Exp $
+ * $Id: in.h,v 1.9 1995/03/16 18:22:26 wollman Exp $
*/
#ifndef _NETINET_IN_H_
@@ -49,6 +49,7 @@
#define IPPROTO_ICMP 1 /* control message protocol */
#define IPPROTO_IGMP 2 /* group mgmt protocol */
#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
+#define IPPROTO_IPIP 4 /* IP encapsulation in IP */
#define IPPROTO_TCP 6 /* tcp */
#define IPPROTO_EGP 8 /* exterior gateway protocol */
#define IPPROTO_PUP 12 /* pup */
@@ -166,14 +167,15 @@ struct ip_opts {
#define IP_MULTICAST_VIF 14 /* set/get IP mcast virt. iface */
#define IP_RSVP_ON 15 /* enable RSVP in kernel */
#define IP_RSVP_OFF 16 /* disable RSVP in kernel */
-
+#define IP_RSVP_VIF_ON 17 /* set RSVP per-vif socket */
+#define IP_RSVP_VIF_OFF 18 /* unset RSVP per-vif socket */
/*
* Defaults and limits for options
*/
#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */
#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */
-#define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */
+#define IP_MAX_MEMBERSHIPS 20 /* per socket */
/*
* Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 1a5f6d9..d1d8677 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -81,7 +81,8 @@ int tp_init(), tp_slowtimo(), tp_drain(), tp_usrreq();
void eoninput(), eonctlinput(), eonprotoinit();
#endif /* EON */
-void multiencap_decap(struct mbuf *);
+void rsvp_input(struct mbuf *, int);
+void ipip_input(struct mbuf *, int);
extern struct domain inetdomain;
@@ -118,12 +119,12 @@ struct protosw inetsw[] = {
igmp_init, igmp_fasttimo, igmp_slowtimo, 0, igmp_sysctl
},
{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR,
- rip_input, rip_output, 0, rip_ctloutput,
+ rsvp_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
0, 0, 0, 0,
},
{ SOCK_RAW, &inetdomain, IPPROTO_ENCAP, PR_ATOMIC|PR_ADDR,
- multiencap_decap, rip_output, 0, rip_ctloutput,
+ ipip_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
0, 0, 0, 0,
},
@@ -160,7 +161,7 @@ struct protosw inetsw[] = {
extern int in_inithead(void **, int);
struct domain inetdomain =
- { AF_INET, "internet", 0, 0, 0,
+ { AF_INET, "internet", 0, 0, 0,
inetsw, &inetsw[sizeof(inetsw)/sizeof(inetsw[0])], 0,
in_inithead, 32, sizeof(struct sockaddr_in)
};
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 22a4f45..a463193 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -65,6 +65,8 @@
#include <netinet/ip_fw.h>
#include <sys/socketvar.h>
+int rsvp_on = 0;
+int ip_rsvp_on;
struct socket *ip_rsvpd;
#ifndef IPFORWARDING
@@ -255,12 +257,12 @@ next:
goto next;
/* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
- * matter if it is destined to another node, or whether it is
+ * matter if it is destined to another node, or whether it is
* a multicast one, RSVP wants it! and prevents it from being forwarded
* anywhere else. Also checks if the rsvp daemon is running before
* grabbing the packet.
*/
- if (ip_rsvpd != NULL && ip->ip_p==IPPROTO_RSVP)
+ if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
goto ours;
/*
@@ -357,9 +359,9 @@ ours:
/*
* If packet came to us we count it...
- * This way we count all incoming packets which has
+ * This way we count all incoming packets which has
* not been forwarded...
- * Do not convert ip_len to host byte order when
+ * Do not convert ip_len to host byte order when
* counting,ppl already made it for us before..
*/
if (ip_acct_cnt_ptr!=NULL)
@@ -747,7 +749,7 @@ ip_dooptions(m)
char buf[4*sizeof "123"];
strcpy(buf, inet_ntoa(ip->ip_dst));
- log(LOG_WARNING,
+ log(LOG_WARNING,
"attempted source route from %s to %s\n",
inet_ntoa(ip->ip_src), buf);
type = ICMP_UNREACH;
@@ -1207,17 +1209,17 @@ ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
case IPCTL_DEFTTL:
return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_defttl));
case IPCTL_SOURCEROUTE:
- return (sysctl_int(oldp, oldlenp, newp, newlen,
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
&ip_dosourceroute));
#ifdef notyet
case IPCTL_DEFMTU:
return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtu));
#endif
case IPCTL_RTEXPIRE:
- return (sysctl_int(oldp, oldlenp, newp, newlen,
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
&rtq_reallyold));
case IPCTL_RTMINEXPIRE:
- return (sysctl_int(oldp, oldlenp, newp, newlen,
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
&rtq_minreallyold));
case IPCTL_RTMAXCACHE:
return (sysctl_int(oldp, oldlenp, newp, newlen,
@@ -1239,6 +1241,14 @@ ip_rsvp_init(struct socket *so)
return EADDRINUSE;
ip_rsvpd = so;
+ /*
+ * This may seem silly, but we need to be sure we don't over-increment
+ * the RSVP counter, in case something slips up.
+ */
+ if (!ip_rsvp_on) {
+ ip_rsvp_on = 1;
+ rsvp_on++;
+ }
return 0;
}
@@ -1247,5 +1257,13 @@ int
ip_rsvp_done(void)
{
ip_rsvpd = NULL;
+ /*
+ * This may seem silly, but we need to be sure we don't over-decrement
+ * the RSVP counter, in case something slips up.
+ */
+ if (ip_rsvp_on) {
+ ip_rsvp_on = 0;
+ rsvp_on--;
+ }
return 0;
}
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index 7226fd4..2abb1e1 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -6,8 +6,9 @@
* Modified by Mark J. Steiglitz, Stanford, May, 1991
* Modified by Van Jacobson, LBL, January 1993
* Modified by Ajit Thyagarajan, PARC, August 1993
+ * Modified by Bill Fenner, PARC, April 1995
*
- * MROUTING 1.8
+ * MROUTING Revision: 3.5
*/
@@ -19,6 +20,7 @@
#include <sys/protosw.h>
#include <sys/errno.h>
#include <sys/time.h>
+#include <sys/kernel.h>
#include <sys/ioctl.h>
#include <sys/syslog.h>
#include <sys/queue.h>
@@ -33,6 +35,7 @@
#include <netinet/igmp.h>
#include <netinet/igmp_var.h>
#include <netinet/ip_mroute.h>
+#include <netinet/udp.h>
#ifndef NTOHL
#if BYTE_ORDER != BIG_ENDIAN
@@ -48,18 +51,20 @@
#endif
#endif
+extern int rsvp_on;
+
#ifndef MROUTING
/*
* Dummy routines and globals used when multicast routing is not compiled in.
*/
-u_int ip_mrtproto = 0;
struct socket *ip_mrouter = NULL;
+u_int ip_mrtproto = 0;
struct mrtstat mrtstat;
-
+u_int rsvpdebug = 0;
int
-_ip_mrouter_cmd(cmd, so, m)
+_ip_mrouter_set(cmd, so, m)
int cmd;
struct socket *so;
struct mbuf *m;
@@ -67,7 +72,19 @@ _ip_mrouter_cmd(cmd, so, m)
return(EOPNOTSUPP);
}
-int (*ip_mrouter_cmd)(int, struct socket *, struct mbuf *) = _ip_mrouter_cmd;
+int (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = _ip_mrouter_set;
+
+
+int
+_ip_mrouter_get(cmd, so, m)
+ int cmd;
+ struct socket *so;
+ struct mbuf **m;
+{
+ return(EOPNOTSUPP);
+}
+
+int (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = _ip_mrouter_get;
int
_ip_mrouter_done()
@@ -98,14 +115,72 @@ _mrt_ioctl(int req, caddr_t data, struct proc *p)
int (*mrt_ioctl)(int, caddr_t, struct proc *) = _mrt_ioctl;
-void multiencap_decap(struct mbuf *m) { /* XXX must fixup manually */
+void
+rsvp_input(m, iphlen) /* XXX must fixup manually */
+ struct mbuf *m;
+ int iphlen;
+{
+ /* Can still get packets with rsvp_on = 0 if there is a local member
+ * of the group to which the RSVP packet is addressed. But in this
+ * case we want to throw the packet away.
+ */
+ if (!rsvp_on) {
+ m_freem(m);
+ return;
+ }
+
+ if (ip_rsvpd != NULL) {
+ if (rsvpdebug)
+ printf("rsvp_input: Sending packet up old-style socket\n");
+ rip_input(m);
+ return;
+ }
+ /* Drop the packet */
+ m_freem(m);
+}
+
+void ipip_input(struct mbuf *m) { /* XXX must fixup manually */
rip_input(m);
}
int (*legal_vif_num)(int) = 0;
+/*
+ * This should never be called, since IP_MULTICAST_VIF should fail, but
+ * just in case it does get called, the code a little lower in ip_output
+ * will assign the packet a local address.
+ */
+u_long
+_ip_mcast_src(int vifi) { return INADDR_ANY; }
+u_long (*ip_mcast_src)(int) = _ip_mcast_src;
+
+int
+ip_rsvp_vif_init(so, m)
+ struct socket *so;
+ struct mbuf *m;
+{
+ return(EINVAL);
+}
+
+int
+ip_rsvp_vif_done(so, m)
+ struct socket *so;
+ struct mbuf *m;
+{
+ return(EINVAL);
+}
+
+void
+ip_rsvp_force_done(so)
+ struct socket *so;
+{
+ return;
+}
+
#else /* MROUTING */
+#define M_HASCL(m) ((m)->m_flags & M_EXT)
+
#define INSIZ sizeof(struct in_addr)
#define same(a1, a2) \
(bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0)
@@ -130,16 +205,23 @@ extern int ip_mrtproto;
#define RTE_FOUND 0x2
struct mbuf *mfctable[MFCTBLSIZ];
+u_char nexpire[MFCTBLSIZ];
struct vif viftable[MAXVIFS];
u_int mrtdebug = 0; /* debug level */
+#define DEBUG_MFC 0x02
+#define DEBUG_FORWARD 0x04
+#define DEBUG_EXPIRE 0x08
+#define DEBUG_XMIT 0x10
u_int tbfdebug = 0; /* tbf debug level */
+u_int rsvpdebug = 0; /* rsvp debug level */
-u_long timeout_val = 0; /* count of outstanding upcalls */
+#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */
+#define UPCALL_EXPIRE 6 /* number of timeouts */
/*
* Define the token bucket filter structures
- * tbftable -> each vif has one of these for storing info
- * qtable -> each interface has an associated queue of pkts
+ * tbftable -> each vif has one of these for storing info
+ * qtable -> each interface has an associated queue of pkts
*/
struct tbf tbftable[MAXVIFS];
@@ -156,7 +238,7 @@ struct pkt_queue qtable[MAXVIFS][MAXQSIZE];
struct ifnet multicast_decap_if[MAXVIFS];
#define ENCAP_TTL 64
-#define ENCAP_PROTO 4
+#define ENCAP_PROTO IPPROTO_IPIP /* 4 */
/* prototype IP hdr for encapsulated packets */
struct ip multicast_encap_iphdr = {
@@ -169,7 +251,7 @@ struct ip multicast_encap_iphdr = {
sizeof(struct ip), /* total length */
0, /* id */
0, /* frag offset */
- ENCAP_TTL, ENCAP_PROTO,
+ ENCAP_TTL, ENCAP_PROTO,
0, /* checksum */
};
@@ -178,115 +260,82 @@ struct ip multicast_encap_iphdr = {
*/
static vifi_t numvifs = 0;
static void (*encap_oldrawip)() = 0;
+static int have_encap_tunnel = 0;
/*
- * one-back cache used by multiencap_decap to locate a tunnel's vif
+ * one-back cache used by ipip_input to locate a tunnel's vif
* given a datagram's src ip address.
*/
static u_long last_encap_src;
static struct vif *last_encap_vif;
-static u_long nethash_fc(u_long, u_long);
-static struct mfc *mfcfind(u_long, u_long);
-int get_sg_cnt(struct sioc_sg_req *);
-int get_vif_cnt(struct sioc_vif_req *);
-int get_vifs(caddr_t);
+static int get_sg_cnt(struct sioc_sg_req *);
+static int get_vif_cnt(struct sioc_vif_req *);
+int ip_mrouter_init(struct socket *, struct mbuf *);
static int add_vif(struct vifctl *);
static int del_vif(vifi_t *);
static int add_mfc(struct mfcctl *);
-static int del_mfc(struct delmfcctl *);
-static void cleanup_cache(void *);
-static int ip_mdq(struct mbuf *, struct ifnet *, u_long, struct mfc *,
- struct ip_moptions *);
+static int del_mfc(struct mfcctl *);
+static int get_version(struct mbuf *);
+static int get_assert(struct mbuf *);
+static int set_assert(int *);
+static void expire_upcalls(void *);
+static int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *,
+ vifi_t);
static void phyint_send(struct ip *, struct vif *, struct mbuf *);
-static void srcrt_send(struct ip *, struct vif *, struct mbuf *);
static void encap_send(struct ip *, struct vif *, struct mbuf *);
-void tbf_control(struct vif *, struct mbuf *, struct ip *, u_long,
+static void tbf_control(struct vif *, struct mbuf *, struct ip *, u_long,
struct ip_moptions *);
-void tbf_queue(struct vif *, struct mbuf *, struct ip *, struct ip_moptions *);
-void tbf_process_q(struct vif *);
-void tbf_dequeue(struct vif *, int);
-void tbf_reprocess_q(void *);
-int tbf_dq_sel(struct vif *, struct ip *);
-void tbf_send_packet(struct vif *, struct mbuf *, struct ip_moptions *);
-void tbf_update_tokens(struct vif *);
+static void tbf_queue(struct vif *, struct mbuf *, struct ip *, struct ip_moptions *);
+static void tbf_process_q(struct vif *);
+static void tbf_dequeue(struct vif *, int);
+static void tbf_reprocess_q(void *);
+static int tbf_dq_sel(struct vif *, struct ip *);
+static void tbf_send_packet(struct vif *, struct mbuf *, struct ip_moptions *);
+static void tbf_update_tokens(struct vif *);
static int priority(struct vif *, struct ip *);
-static int ip_mrouter_init(struct socket *);
-void multiencap_decap(struct mbuf *m);
+void multiencap_decap(struct mbuf *);
/*
- * A simple hash function: returns MFCHASHMOD of the low-order octet of
- * the argument's network or subnet number and the multicast group assoc.
+ * whether or not special PIM assert processing is enabled.
*/
-static u_long
-nethash_fc(m,n)
- register u_long m;
- register u_long n;
-{
- struct in_addr in1;
- struct in_addr in2;
-
- in1.s_addr = m;
- m = in_netof(in1);
- while ((m & 0xff) == 0) m >>= 8;
-
- in2.s_addr = n;
- n = in_netof(in2);
- while ((n & 0xff) == 0) n >>= 8;
-
- return (MFCHASHMOD(m) ^ MFCHASHMOD(n));
-}
+static int pim_assert;
+/*
+ * Rate limit for assert notification messages, in usec
+ */
+#define ASSERT_MSG_TIME 3000000
/*
- * this is a direct-mapped cache used to speed the mapping from a
- * datagram source address to the associated multicast route. Note
- * that unlike mrttable, the hash is on IP address, not IP net number.
+ * Hash function for a source, group entry
*/
-#define MFCHASHSIZ 1024
-#define MFCHASH(a, g) ((((a) >> 20) ^ ((a) >> 10) ^ (a) ^ \
- ((g) >> 20) ^ ((g) >> 10) ^ (g)) & (MFCHASHSIZ-1))
-struct mfc *mfchash[MFCHASHSIZ];
+#define MFCHASH(a, g) MFCHASHMOD(((a) >> 20) ^ ((a) >> 10) ^ (a) ^ \
+ ((g) >> 20) ^ ((g) >> 10) ^ (g))
/*
* Find a route for a given origin IP address and Multicast group address
* Type of service parameter to be added in the future!!!
*/
+
#define MFCFIND(o, g, rt) { \
- register u_int _mrhasho = o; \
- register u_int _mrhashg = g; \
- _mrhasho = MFCHASH(_mrhasho, _mrhashg); \
+ register struct mbuf *_mb_rt = mfctable[MFCHASH(o,g)]; \
+ register struct mfc *_rt = NULL; \
+ rt = NULL; \
++mrtstat.mrts_mfc_lookups; \
- rt = mfchash[_mrhasho]; \
- if ((rt == NULL) || \
- ((o & rt->mfc_originmask.s_addr) != rt->mfc_origin.s_addr) || \
- (g != rt->mfc_mcastgrp.s_addr)) \
- if ((rt = mfcfind(o, g)) != NULL) \
- mfchash[_mrhasho] = rt; \
+ while (_mb_rt) { \
+ _rt = mtod(_mb_rt, struct mfc *); \
+ if ((_rt->mfc_origin.s_addr == o) && \
+ (_rt->mfc_mcastgrp.s_addr == g) && \
+ (_mb_rt->m_act == NULL)) { \
+ rt = _rt; \
+ break; \
+ } \
+ _mb_rt = _mb_rt->m_next; \
+ } \
+ if (rt == NULL) { \
+ ++mrtstat.mrts_mfc_misses; \
+ } \
}
-/*
- * Find route by examining hash table entries
- */
-static struct mfc *
-mfcfind(origin, mcastgrp)
- u_long origin;
- u_long mcastgrp;
-{
- register struct mbuf *mb_rt;
- register struct mfc *rt;
- register u_long hash;
-
- hash = nethash_fc(origin, mcastgrp);
- for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) {
- rt = mtod(mb_rt, struct mfc *);
- if (((origin & rt->mfc_originmask.s_addr) == rt->mfc_origin.s_addr) &&
- (mcastgrp == rt->mfc_mcastgrp.s_addr) &&
- (mb_rt->m_act == NULL))
- return (rt);
- }
- mrtstat.mrts_mfc_misses++;
- return NULL;
-}
/*
* Macros to compute elapsed time efficiently
@@ -313,30 +362,63 @@ mfcfind(origin, mcastgrp)
#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
(a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
+#ifdef UPCALL_TIMING
+u_long upcall_data[51];
+static void collate(struct timeval *);
+#endif /* UPCALL_TIMING */
+
+
/*
- * Handle DVMRP setsockopt commands to modify the multicast routing tables.
+ * Handle MRT setsockopt commands to modify the multicast routing tables.
*/
int
-X_ip_mrouter_cmd(cmd, so, m)
+X_ip_mrouter_set(cmd, so, m)
int cmd;
struct socket *so;
struct mbuf *m;
{
- if (cmd != DVMRP_INIT && so != ip_mrouter) return EACCES;
+ if (cmd != MRT_INIT && so != ip_mrouter) return EACCES;
switch (cmd) {
- case DVMRP_INIT: return ip_mrouter_init(so);
- case DVMRP_DONE: return ip_mrouter_done();
- case DVMRP_ADD_VIF: return add_vif (mtod(m, struct vifctl *));
- case DVMRP_DEL_VIF: return del_vif (mtod(m, vifi_t *));
- case DVMRP_ADD_MFC: return add_mfc (mtod(m, struct mfcctl *));
- case DVMRP_DEL_MFC: return del_mfc (mtod(m, struct delmfcctl *));
+ case MRT_INIT: return ip_mrouter_init(so, m);
+ case MRT_DONE: return ip_mrouter_done();
+ case MRT_ADD_VIF: return add_vif (mtod(m, struct vifctl *));
+ case MRT_DEL_VIF: return del_vif (mtod(m, vifi_t *));
+ case MRT_ADD_MFC: return add_mfc (mtod(m, struct mfcctl *));
+ case MRT_DEL_MFC: return del_mfc (mtod(m, struct mfcctl *));
+ case MRT_ASSERT: return set_assert(mtod(m, int *));
default: return EOPNOTSUPP;
}
}
#ifndef MROUTE_LKM
-int (*ip_mrouter_cmd)(int, struct socket *, struct mbuf *) = X_ip_mrouter_cmd;
+int (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = X_ip_mrouter_set;
+#endif
+
+/*
+ * Handle MRT getsockopt commands
+ */
+int
+X_ip_mrouter_get(cmd, so, m)
+ int cmd;
+ struct socket *so;
+ struct mbuf **m;
+{
+ struct mbuf *mb;
+
+ if (so != ip_mrouter) return EACCES;
+
+ *m = mb = m_get(M_WAIT, MT_SOOPTS);
+
+ switch (cmd) {
+ case MRT_VERSION: return get_version(mb);
+ case MRT_ASSERT: return get_assert(mb);
+ default: return EOPNOTSUPP;
+ }
+}
+
+#ifndef MROUTE_LKM
+int (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = X_ip_mrouter_get;
#endif
/*
@@ -350,18 +432,15 @@ X_mrt_ioctl(cmd, data)
int error = 0;
switch (cmd) {
- case (SIOCGETVIFINF): /* Read Virtual Interface (m/cast) */
- return (get_vifs(data));
- break;
- case (SIOCGETVIFCNT):
- return (get_vif_cnt((struct sioc_vif_req *)data));
- break;
- case (SIOCGETSGCNT):
- return (get_sg_cnt((struct sioc_sg_req *)data));
- break;
+ case (SIOCGETVIFCNT):
+ return (get_vif_cnt((struct sioc_vif_req *)data));
+ break;
+ case (SIOCGETSGCNT):
+ return (get_sg_cnt((struct sioc_sg_req *)data));
+ break;
default:
- return (EINVAL);
- break;
+ return (EINVAL);
+ break;
}
return error;
}
@@ -371,9 +450,9 @@ int (*mrt_ioctl)(int, caddr_t, struct proc *) = X_mrt_ioctl;
#endif
/*
- * returns the packet count for the source group provided
+ * returns the packet, byte, rpf-failure count for the source group provided
*/
-int
+static int
get_sg_cnt(req)
register struct sioc_sg_req *req;
{
@@ -383,83 +462,73 @@ get_sg_cnt(req)
s = splnet();
MFCFIND(req->src.s_addr, req->grp.s_addr, rt);
splx(s);
- if (rt != NULL)
- req->count = rt->mfc_pkt_cnt;
- else
- req->count = 0xffffffff;
+ if (rt != NULL) {
+ req->pktcnt = rt->mfc_pkt_cnt;
+ req->bytecnt = rt->mfc_byte_cnt;
+ req->wrong_if = rt->mfc_wrong_if;
+ } else
+ req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
return 0;
}
/*
- * returns the input and output packet counts on the interface provided
+ * returns the input and output packet and byte counts on the vif provided
*/
-int
+static int
get_vif_cnt(req)
register struct sioc_vif_req *req;
{
register vifi_t vifi = req->vifi;
+ if (vifi >= numvifs) return EINVAL;
+
req->icount = viftable[vifi].v_pkt_in;
req->ocount = viftable[vifi].v_pkt_out;
+ req->ibytes = viftable[vifi].v_bytes_in;
+ req->obytes = viftable[vifi].v_bytes_out;
return 0;
}
-int
-get_vifs(data)
- char *data;
-{
- struct vif_conf *vifc = (struct vif_conf *)data;
- struct vif_req *vifrp, vifr;
- int space, error=0;
-
- vifi_t vifi;
- int s;
-
- space = vifc->vifc_len;
- vifrp = vifc->vifc_req;
-
- s = splnet();
- vifc->vifc_num=numvifs;
-
- for (vifi = 0; vifi < numvifs; vifi++, vifrp++) {
- if (viftable[vifi].v_lcl_addr.s_addr != 0) {
- vifr.v_flags=viftable[vifi].v_flags;
- vifr.v_threshold=viftable[vifi].v_threshold;
- vifr.v_lcl_addr=viftable[vifi].v_lcl_addr;
- vifr.v_rmt_addr=viftable[vifi].v_rmt_addr;
- strncpy(vifr.v_if_name,viftable[vifi].v_ifp->if_name,IFNAMSIZ);
- if ((space -= sizeof(vifr)) < 0) {
- splx(s);
- return(ENOSPC);
- }
- error = copyout((caddr_t)&vifr,(caddr_t)vifrp,(u_int)(sizeof vifr));
- if (error) {
- splx(s);
- return(error);
- }
- }
- }
- splx(s);
- return 0;
-}
/*
* Enable multicast routing
*/
-static int
-ip_mrouter_init(so)
+int
+ip_mrouter_init(so, m)
struct socket *so;
+ struct mbuf *m;
{
+ int *v;
+ int i;
+
+ if (mrtdebug)
+ log(LOG_DEBUG,"ip_mrouter_init: so_type = %d, pr_protocol = %d",
+ so->so_type, so->so_proto->pr_protocol);
+
if (so->so_type != SOCK_RAW ||
so->so_proto->pr_protocol != IPPROTO_IGMP) return EOPNOTSUPP;
+ if (!m || (m->m_len != sizeof(int *)))
+ return ENOPROTOOPT;
+
+ v = mtod(m, int *);
+ if (*v != 1)
+ return ENOPROTOOPT;
+
if (ip_mrouter != NULL) return EADDRINUSE;
ip_mrouter = so;
+ bzero((caddr_t)mfctable, sizeof(mfctable));
+ bzero((caddr_t)nexpire, sizeof(nexpire));
+
+ pim_assert = 0;
+
+ timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
+
if (mrtdebug)
- log(LOG_DEBUG, "ip_mrouter_init\n");
+ log(LOG_DEBUG, "ip_mrouter_init");
return 0;
}
@@ -475,6 +544,7 @@ X_ip_mrouter_done()
struct ifnet *ifp;
struct ifreq ifr;
struct mbuf *mb_rt;
+ struct mfc *rt;
struct mbuf *m;
struct rtdetq *rte;
int s;
@@ -499,52 +569,44 @@ X_ip_mrouter_done()
bzero((caddr_t)tbftable, sizeof(tbftable));
bzero((caddr_t)viftable, sizeof(viftable));
numvifs = 0;
+ pim_assert = 0;
+
+ untimeout(expire_upcalls, (caddr_t)NULL);
/*
- * Check if any outstanding timeouts remain
+ * Free all multicast forwarding cache entries.
*/
- if (timeout_val != 0)
- for (i = 0; i < MFCTBLSIZ; i++) {
- mb_rt = mfctable[i];
- while (mb_rt) {
- if ( mb_rt->m_act != NULL) {
- untimeout(cleanup_cache, (caddr_t)mb_rt);
- while (mb_rt->m_act) {
- m = mb_rt->m_act;
- mb_rt->m_act = m->m_act;
- rte = mtod(m, struct rtdetq *);
- m_freem(rte->m);
- m_free(m);
- }
- timeout_val--;
+ for (i = 0; i < MFCTBLSIZ; i++) {
+ mb_rt = mfctable[i];
+ while (mb_rt) {
+ if (mb_rt->m_act != NULL) {
+ while (mb_rt->m_act) {
+ m = mb_rt->m_act;
+ mb_rt->m_act = m->m_act;
+ rte = mtod(m, struct rtdetq *);
+ m_freem(rte->m);
+ m_free(m);
}
- mb_rt = mb_rt->m_next;
}
- if (timeout_val == 0)
- break;
+ mb_rt = m_free(mb_rt);
}
-
- /*
- * Free all multicast forwarding cache entries.
- */
- for (i = 0; i < MFCTBLSIZ; i++)
- m_freem(mfctable[i]);
+ }
bzero((caddr_t)mfctable, sizeof(mfctable));
- bzero((caddr_t)mfchash, sizeof(mfchash));
/*
* Reset de-encapsulation cache
*/
last_encap_src = NULL;
last_encap_vif = NULL;
-
+ have_encap_tunnel = 0;
+
ip_mrouter = NULL;
splx(s);
if (mrtdebug)
- log(LOG_DEBUG, "ip_mrouter_done\n");
+ log(LOG_DEBUG, "ip_mrouter_done");
return 0;
}
@@ -553,6 +615,51 @@ X_ip_mrouter_done()
int (*ip_mrouter_done)(void) = X_ip_mrouter_done;
#endif
+static int
+get_version(mb)
+ struct mbuf *mb;
+{
+ int *v;
+
+ v = mtod(mb, int *);
+
+ *v = 0x0305; /* XXX !!!! */
+ mb->m_len = sizeof(int);
+
+ return 0;
+}
+
+/*
+ * Set PIM assert processing global
+ */
+static int
+set_assert(i)
+ int *i;
+{
+ if ((*i != 1) && (*i != 0))
+ return EINVAL;
+
+ pim_assert = *i;
+
+ return 0;
+}
+
+/*
+ * Get PIM assert processing global
+ */
+static int
+get_assert(m)
+ struct mbuf *m;
+{
+ int *i;
+
+ i = mtod(m, int *);
+
+ *i = pim_assert;
+
+ return 0;
+}
+
/*
* Add a vif to the vif table
*/
@@ -579,20 +686,28 @@ add_vif(vifcp)
if (vifcp->vifc_flags & VIFF_TUNNEL) {
if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) {
- if (encap_oldrawip == 0) {
- extern struct protosw inetsw[];
- register u_char pr = ip_protox[ENCAP_PROTO];
-
- encap_oldrawip = inetsw[pr].pr_input;
- inetsw[pr].pr_input = multiencap_decap;
- for (s = 0; s < MAXVIFS; ++s) {
- multicast_decap_if[s].if_name = "mdecap";
- multicast_decap_if[s].if_unit = s;
+ /*
+ * An encapsulating tunnel is wanted. Tell ipip_input() to
+ * start paying attention to encapsulated packets.
+ */
+ if (have_encap_tunnel == 0) {
+ have_encap_tunnel = 1;
+ for (s = 0; s < MAXVIFS; ++s) {
+ multicast_decap_if[s].if_name = "mdecap";
+ multicast_decap_if[s].if_unit = s;
+ }
}
- }
- ifp = &multicast_decap_if[vifcp->vifc_vifi];
+ /*
+ * Set interface to fake encapsulator interface
+ */
+ ifp = &multicast_decap_if[vifcp->vifc_vifi];
+ /*
+ * Prepare cached route entry
+ */
+ bzero(&vifp->v_route, sizeof(vifp->v_route));
} else {
- ifp = 0;
+ log(LOG_ERR, "Source routed tunnels not supported.");
+ return EOPNOTSUPP;
}
} else {
/* Make sure the interface supports multicast */
@@ -622,22 +737,26 @@ add_vif(vifcp)
vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
vifp->v_ifp = ifp;
vifp->v_rate_limit= vifcp->vifc_rate_limit;
+ vifp->v_rsvp_on = 0;
+ vifp->v_rsvpd = NULL;
/* initialize per vif pkt counters */
vifp->v_pkt_in = 0;
vifp->v_pkt_out = 0;
+ vifp->v_bytes_in = 0;
+ vifp->v_bytes_out = 0;
splx(s);
/* Adjust numvifs up if the vifi is higher than numvifs */
if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1;
if (mrtdebug)
- log(LOG_DEBUG, "add_vif #%d, lcladdr %x, %s %x, thresh %x, rate %d\n",
- vifcp->vifc_vifi,
+ log(LOG_DEBUG, "add_vif #%d, lcladdr %x, %s %x, thresh %x, rate %d",
+ vifcp->vifc_vifi,
ntohl(vifcp->vifc_lcl_addr.s_addr),
(vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask",
ntohl(vifcp->vifc_rmt_addr.s_addr),
vifcp->vifc_threshold,
- vifcp->vifc_rate_limit);
+ vifcp->vifc_rate_limit);
return 0;
}
@@ -685,7 +804,7 @@ del_vif(vifip)
splx(s);
if (mrtdebug)
- log(LOG_DEBUG, "del_vif %d, numvifs %d\n", *vifip, numvifs);
+ log(LOG_DEBUG, "del_vif %d, numvifs %d", *vifip, numvifs);
return 0;
}
@@ -698,9 +817,7 @@ add_mfc(mfccp)
struct mfcctl *mfccp;
{
struct mfc *rt;
- struct mfc *rt1 = 0;
register struct mbuf *mb_rt;
- struct mbuf *prev_mb_rt;
u_long hash;
struct mbuf *mb_ntry;
struct rtdetq *rte;
@@ -708,81 +825,77 @@ add_mfc(mfccp)
int s;
int i;
- rt = mfcfind(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr);
+ MFCFIND(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr, rt);
/* If an entry already exists, just update the fields */
if (rt) {
- if (mrtdebug)
- log(LOG_DEBUG,"add_mfc update o %x g %x m %x p %x\n",
+ if (mrtdebug & DEBUG_MFC)
+ log(LOG_DEBUG,"add_mfc update o %x g %x p %x",
ntohl(mfccp->mfcc_origin.s_addr),
ntohl(mfccp->mfcc_mcastgrp.s_addr),
- ntohl(mfccp->mfcc_originmask.s_addr),
mfccp->mfcc_parent);
s = splnet();
rt->mfc_parent = mfccp->mfcc_parent;
for (i = 0; i < numvifs; i++)
- VIFM_COPY(mfccp->mfcc_ttls[i], rt->mfc_ttls[i]);
+ rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
splx(s);
return 0;
}
- /*
+ /*
* Find the entry for which the upcall was made and update
*/
s = splnet();
- hash = nethash_fc(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr);
- for (prev_mb_rt = mb_rt = mfctable[hash], nstl = 0;
- mb_rt; prev_mb_rt = mb_rt, mb_rt = mb_rt->m_next) {
+ hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr);
+ for (mb_rt = mfctable[hash], nstl = 0; mb_rt; mb_rt = mb_rt->m_next) {
rt = mtod(mb_rt, struct mfc *);
- if (((rt->mfc_origin.s_addr & mfccp->mfcc_originmask.s_addr)
- == mfccp->mfcc_origin.s_addr) &&
+ if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) &&
(rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) &&
(mb_rt->m_act != NULL)) {
+
+ if (nstl++)
+ log(LOG_ERR, "add_mfc %s o %x g %x p %x dbx %x",
+ "multiple kernel entries",
+ ntohl(mfccp->mfcc_origin.s_addr),
+ ntohl(mfccp->mfcc_mcastgrp.s_addr),
+ mfccp->mfcc_parent, mb_rt->m_act);
+
+ if (mrtdebug & DEBUG_MFC)
+ log(LOG_DEBUG,"add_mfc o %x g %x p %x dbg %x",
+ ntohl(mfccp->mfcc_origin.s_addr),
+ ntohl(mfccp->mfcc_mcastgrp.s_addr),
+ mfccp->mfcc_parent, mb_rt->m_act);
- if (!nstl++) {
- if (mrtdebug)
- log(LOG_DEBUG,"add_mfc o %x g %x m %x p %x dbg %x\n",
- ntohl(mfccp->mfcc_origin.s_addr),
- ntohl(mfccp->mfcc_mcastgrp.s_addr),
- ntohl(mfccp->mfcc_originmask.s_addr),
- mfccp->mfcc_parent, mb_rt->m_act);
-
- rt->mfc_origin = mfccp->mfcc_origin;
- rt->mfc_originmask = mfccp->mfcc_originmask;
- rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
- rt->mfc_parent = mfccp->mfcc_parent;
- for (i = 0; i < numvifs; i++)
- VIFM_COPY(mfccp->mfcc_ttls[i], rt->mfc_ttls[i]);
- /* initialize pkt counters per src-grp */
- rt->mfc_pkt_cnt = 0;
- rt1 = rt;
- }
+ rt->mfc_origin = mfccp->mfcc_origin;
+ rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
+ rt->mfc_parent = mfccp->mfcc_parent;
+ for (i = 0; i < numvifs; i++)
+ rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
+ /* initialize pkt counters per src-grp */
+ rt->mfc_pkt_cnt = 0;
+ rt->mfc_byte_cnt = 0;
+ rt->mfc_wrong_if = 0;
+ rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;
- /* prevent cleanup of cache entry */
- untimeout(cleanup_cache, (caddr_t)mb_rt);
- timeout_val--;
+ rt->mfc_expire = 0; /* Don't clean this guy up */
+ nexpire[hash]--;
/* free packets Qed at the end of this entry */
while (mb_rt->m_act) {
mb_ntry = mb_rt->m_act;
rte = mtod(mb_ntry, struct rtdetq *);
- ip_mdq(rte->m, rte->ifp, rte->tunnel_src,
- rt1, rte->imo);
+/* #ifdef RSVP_ISI */
+ ip_mdq(rte->m, rte->ifp, rt, -1);
+/* #endif */
mb_rt->m_act = mb_ntry->m_act;
m_freem(rte->m);
+#ifdef UPCALL_TIMING
+ collate(&(rte->t));
+#endif /* UPCALL_TIMING */
m_free(mb_ntry);
}
-
- /*
- * If more than one entry was created for a single upcall
- * delete that entry
- */
- if (nstl > 1) {
- MFREE(mb_rt, prev_mb_rt->m_next);
- mb_rt = prev_mb_rt;
- }
}
}
@@ -790,29 +903,31 @@ add_mfc(mfccp)
* It is possible that an entry is being inserted without an upcall
*/
if (nstl == 0) {
- if (mrtdebug)
- log(LOG_DEBUG,"add_mfc no upcall h %d o %x g %x m %x p %x\n",
+ if (mrtdebug & DEBUG_MFC)
+ log(LOG_DEBUG,"add_mfc no upcall h %d o %x g %x p %x",
hash, ntohl(mfccp->mfcc_origin.s_addr),
ntohl(mfccp->mfcc_mcastgrp.s_addr),
- ntohl(mfccp->mfcc_originmask.s_addr),
mfccp->mfcc_parent);
-
- for (prev_mb_rt = mb_rt = mfctable[hash];
- mb_rt; prev_mb_rt = mb_rt, mb_rt = mb_rt->m_next) {
-
+
+ for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) {
+
rt = mtod(mb_rt, struct mfc *);
- if (((rt->mfc_origin.s_addr & mfccp->mfcc_originmask.s_addr)
- == mfccp->mfcc_origin.s_addr) &&
+ if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) &&
(rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) {
rt->mfc_origin = mfccp->mfcc_origin;
- rt->mfc_originmask = mfccp->mfcc_originmask;
rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
rt->mfc_parent = mfccp->mfcc_parent;
for (i = 0; i < numvifs; i++)
- VIFM_COPY(mfccp->mfcc_ttls[i], rt->mfc_ttls[i]);
+ rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
/* initialize pkt counters per src-grp */
rt->mfc_pkt_cnt = 0;
+ rt->mfc_byte_cnt = 0;
+ rt->mfc_wrong_if = 0;
+ rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;
+ if (rt->mfc_expire)
+ nexpire[hash]--;
+ rt->mfc_expire = 0;
}
}
if (mb_rt == NULL) {
@@ -822,19 +937,22 @@ add_mfc(mfccp)
splx(s);
return ENOBUFS;
}
-
+
rt = mtod(mb_rt, struct mfc *);
-
+
/* insert new entry at head of hash chain */
rt->mfc_origin = mfccp->mfcc_origin;
- rt->mfc_originmask = mfccp->mfcc_originmask;
rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
rt->mfc_parent = mfccp->mfcc_parent;
for (i = 0; i < numvifs; i++)
- VIFM_COPY(mfccp->mfcc_ttls[i], rt->mfc_ttls[i]);
+ rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
/* initialize pkt counters per src-grp */
rt->mfc_pkt_cnt = 0;
-
+ rt->mfc_byte_cnt = 0;
+ rt->mfc_wrong_if = 0;
+ rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;
+ rt->mfc_expire = 0;
+
/* link into table */
mb_rt->m_next = mfctable[hash];
mfctable[hash] = mb_rt;
@@ -845,56 +963,73 @@ add_mfc(mfccp)
return 0;
}
+#ifdef UPCALL_TIMING
+/*
+ * collect delay statistics on the upcalls
+ */
+static void collate(t)
+register struct timeval *t;
+{
+ register u_long d;
+ register struct timeval tp;
+ register u_long delta;
+
+ GET_TIME(tp);
+
+ if (TV_LT(*t, tp))
+ {
+ TV_DELTA(tp, *t, delta);
+
+ d = delta >> 10;
+ if (d > 50)
+ d = 50;
+
+ ++upcall_data[d];
+ }
+}
+#endif /* UPCALL_TIMING */
+
/*
* Delete an mfc entry
*/
static int
del_mfc(mfccp)
- struct delmfcctl *mfccp;
+ struct mfcctl *mfccp;
{
struct in_addr origin;
struct in_addr mcastgrp;
struct mfc *rt;
struct mbuf *mb_rt;
- struct mbuf *prev_mb_rt;
+ struct mbuf **nptr;
u_long hash;
- struct mfc **cmfc;
- struct mfc **cmfcend;
- int s;
+ int s, i;
origin = mfccp->mfcc_origin;
mcastgrp = mfccp->mfcc_mcastgrp;
- hash = nethash_fc(origin.s_addr, mcastgrp.s_addr);
+ hash = MFCHASH(origin.s_addr, mcastgrp.s_addr);
- if (mrtdebug)
- log(LOG_DEBUG,"del_mfc orig %x mcastgrp %x\n",
+ if (mrtdebug & DEBUG_MFC)
+ log(LOG_DEBUG,"del_mfc orig %x mcastgrp %x",
ntohl(origin.s_addr), ntohl(mcastgrp.s_addr));
- for (prev_mb_rt = mb_rt = mfctable[hash]
- ; mb_rt
- ; prev_mb_rt = mb_rt, mb_rt = mb_rt->m_next) {
+ s = splnet();
+
+ nptr = &mfctable[hash];
+ while ((mb_rt = *nptr) != NULL) {
rt = mtod(mb_rt, struct mfc *);
if (origin.s_addr == rt->mfc_origin.s_addr &&
mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr &&
mb_rt->m_act == NULL)
break;
+
+ nptr = &mb_rt->m_next;
}
if (mb_rt == NULL) {
- return ESRCH;
+ splx(s);
+ return EADDRNOTAVAIL;
}
- s = splnet();
-
- cmfc = mfchash;
- cmfcend = cmfc + MFCHASHSIZ;
- for ( ; cmfc < cmfcend; ++cmfc)
- if (*cmfc == rt)
- *cmfc = 0;
-
- if (prev_mb_rt != mb_rt) { /* if moved past head of list */
- MFREE(mb_rt, prev_mb_rt->m_next);
- } else /* delete head of list, it is in the table */
- mfctable[hash] = m_free(mb_rt);
+ MFREE(mb_rt, *nptr);
splx(s);
@@ -902,13 +1037,34 @@ del_mfc(mfccp)
}
/*
+ * Send a message to mrouted on the multicast routing socket
+ */
+static int
+socket_send(s, mm, src)
+ struct socket *s;
+ struct mbuf *mm;
+ struct sockaddr_in *src;
+{
+ if (s) {
+ if (sbappendaddr(&s->so_rcv,
+ (struct sockaddr *)src,
+ mm, (struct mbuf *)0) != 0) {
+ sorwakeup(s);
+ return 0;
+ }
+ }
+ m_freem(mm);
+ return -1;
+}
+
+/*
* IP multicast forwarding function. This function assumes that the packet
* pointed to by "ip" has arrived on (or is about to be sent to) the interface
* pointed to by "ifp", and the packet is to be relayed to other networks
* that have members of the packet's destination IP multicast group.
*
- * The packet is returned unscathed to the caller, unless it is tunneled
- * or erroneous, in which case a non-zero return value tells the caller to
+ * The packet is returned unscathed to the caller, unless it is
+ * erroneous, in which case a non-zero return value tells the caller to
* discard it.
*/
@@ -922,76 +1078,53 @@ X_ip_mforward(ip, ifp, m, imo)
struct mbuf *m;
struct ip_moptions *imo;
{
- register struct mfc *rt;
+ register struct mfc *rt = 0; /* XXX uninit warning */
register u_char *ipoptions;
- u_long tunnel_src;
static struct sockproto k_igmpproto = { AF_INET, IPPROTO_IGMP };
static struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET };
- static struct sockaddr_in k_igmpdst = { sizeof k_igmpdst, AF_INET };
+ static int srctun = 0;
register struct mbuf *mm;
- register struct ip *k_data;
int s;
+ vifi_t vifi;
+ struct vif *vifp;
- if (mrtdebug > 1)
- log(LOG_DEBUG, "ip_mforward: src %x, dst %x, ifp %x (%s%d)\n",
- ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), ifp,
- ifp->if_name, ifp->if_unit);
+ if (mrtdebug & DEBUG_FORWARD)
+ log(LOG_DEBUG, "ip_mforward: src %x, dst %x, ifp %x",
+ ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), ifp);
if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
(ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) {
/*
- * Packet arrived via a physical interface.
+ * Packet arrived via a physical interface or
+ * an encapsulated tunnel.
*/
- tunnel_src = 0;
} else {
/*
* Packet arrived through a source-route tunnel.
- *
- * A source-route tunneled packet has a single NOP option and a
- * two-element
- * loose-source-and-record-route (LSRR) option immediately following
- * the fixed-size part of the IP header. At this point in processing,
- * the IP header should contain the following IP addresses:
- *
- * original source - in the source address field
- * destination group - in the destination address field
- * remote tunnel end-point - in the first element of LSRR
- * one of this host's addrs - in the second element of LSRR
- *
- * NOTE: RFC-1075 would have the original source and remote tunnel
- * end-point addresses swapped. However, that could cause
- * delivery of ICMP error messages to innocent applications
- * on intermediate routing hosts! Therefore, we hereby
- * change the spec.
- */
-
- /*
- * Verify that the tunnel options are well-formed.
+ * Source-route tunnels are no longer supported.
*/
- if (ipoptions[0] != IPOPT_NOP ||
- ipoptions[2] != 11 || /* LSRR option length */
- ipoptions[3] != 12 || /* LSRR address pointer */
- (tunnel_src = *(u_long *)(&ipoptions[4])) == 0) {
- mrtstat.mrts_bad_tunnel++;
- if (mrtdebug)
- log(LOG_DEBUG,
- "ip_mforward: bad tunnel from %u (%x %x %x %x %x %x)\n",
- ntohl(ip->ip_src.s_addr),
- ipoptions[0], ipoptions[1], ipoptions[2], ipoptions[3],
- *(u_long *)(&ipoptions[4]), *(u_long *)(&ipoptions[8]));
- return 1;
- }
+ if ((srctun++ % 1000) == 0)
+ log(LOG_ERR, "ip_mforward: received source-routed packet from %x",
+ ntohl(ip->ip_src.s_addr));
- /*
- * Delete the tunnel options from the packet.
- */
- ovbcopy((caddr_t)(ipoptions + TUNNEL_LEN), (caddr_t)ipoptions,
- (unsigned)(m->m_len - (IP_HDR_LEN + TUNNEL_LEN)));
- m->m_len -= TUNNEL_LEN;
- ip->ip_len -= TUNNEL_LEN;
- ip->ip_hl -= TUNNEL_LEN >> 2;
+ return 1;
+ }
- ifp = 0;
+ if ((imo) && ((vifi = imo->imo_multicast_vif) < numvifs)) {
+ if (ip->ip_ttl < 255)
+ ip->ip_ttl++; /* compensate for -1 in *_send routines */
+ if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
+ vifp = viftable + vifi;
+ printf("Sending IPPROTO_RSVP from %x to %x on vif %d (%s%s%d)\n",
+ ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), vifi,
+ (vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "",
+ vifp->v_ifp->if_name, vifp->v_ifp->if_unit);
+ }
+ return (ip_mdq(m, ifp, rt, vifi));
+ }
+ if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
+ printf("Warning: IPPROTO_RSVP from %x to %x without vif option\n",
+ ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr));
}
/*
@@ -1000,7 +1133,7 @@ X_ip_mforward(ip, ifp, m, imo)
*/
if (ip->ip_ttl <= 1 ||
ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP)
- return (int)tunnel_src;
+ return 0;
/*
* Determine forwarding vifs from the forwarding cache table
@@ -1011,10 +1144,8 @@ X_ip_mforward(ip, ifp, m, imo)
/* Entry exists, so forward if necessary */
if (rt != NULL) {
splx(s);
- return (ip_mdq(m, ifp, tunnel_src, rt, imo));
- }
-
- else {
+ return (ip_mdq(m, ifp, rt, -1));
+ } else {
/*
* If we don't have a route for packet's origin,
* Make a copy of the packet &
@@ -1027,28 +1158,88 @@ X_ip_mforward(ip, ifp, m, imo)
register struct rtdetq *rte;
register struct mbuf *rte_m;
register u_long hash;
+ register int npkts;
+#ifdef UPCALL_TIMING
+ struct timeval tp;
+
+ GET_TIME(tp);
+#endif
mrtstat.mrts_no_route++;
- if (mrtdebug)
- log(LOG_DEBUG, "ip_mforward: no rte s %x g %x\n",
+ if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC))
+ log(LOG_DEBUG, "ip_mforward: no rte s %x g %x",
ntohl(ip->ip_src.s_addr),
ntohl(ip->ip_dst.s_addr));
+ /*
+ * Allocate mbufs early so that we don't do extra work if we are
+ * just going to fail anyway.
+ */
+ MGET(mb_ntry, M_DONTWAIT, MT_DATA);
+ if (mb_ntry == NULL) {
+ splx(s);
+ return ENOBUFS;
+ }
+ mb0 = m_copy(m, 0, M_COPYALL);
+ if (mb0 == NULL) {
+ m_free(mb_ntry);
+ splx(s);
+ return ENOBUFS;
+ }
+
/* is there an upcall waiting for this packet? */
- hash = nethash_fc(ip->ip_src.s_addr, ip->ip_dst.s_addr);
+ hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr);
for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) {
rt = mtod(mb_rt, struct mfc *);
- if (((ip->ip_src.s_addr & rt->mfc_originmask.s_addr) ==
- rt->mfc_origin.s_addr) &&
+ if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) &&
(ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) &&
(mb_rt->m_act != NULL))
break;
}
if (mb_rt == NULL) {
+ int hlen = ip->ip_hl << 2;
+ int i;
+ struct igmpmsg *im;
+
/* no upcall, so make a new entry */
MGET(mb_rt, M_DONTWAIT, MT_MRTABLE);
if (mb_rt == NULL) {
+ m_free(mb_ntry);
+ m_free(mb0);
+ splx(s);
+ return ENOBUFS;
+ }
+ /* Make a copy of the header to send to the user level process */
+ mm = m_copy(m, 0, hlen);
+ if (mm && (M_HASCL(mm) || mm->m_len < hlen))
+ mm = m_pullup(mm, hlen);
+ if (mm == NULL) {
+ m_free(mb_ntry);
+ m_free(mb0);
+ m_free(mb_rt);
+ splx(s);
+ return ENOBUFS;
+ }
+
+ /*
+ * Send message to routing daemon to install
+ * a route into the kernel table
+ */
+ k_igmpsrc.sin_addr = ip->ip_src;
+
+ im = mtod(mm, struct igmpmsg *);
+ im->im_msgtype = IGMPMSG_NOCACHE;
+ im->im_mbz = 0;
+
+ mrtstat.mrts_upcalls++;
+
+ if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) {
+ log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full");
+ ++mrtstat.mrts_upq_sockfull;
+ m_free(mb_ntry);
+ m_free(mb0);
+ m_free(mb_rt);
splx(s);
return ENOBUFS;
}
@@ -1057,80 +1248,49 @@ X_ip_mforward(ip, ifp, m, imo)
/* insert new entry at head of hash chain */
rt->mfc_origin.s_addr = ip->ip_src.s_addr;
- rt->mfc_originmask.s_addr = (u_long)0xffffffff;
rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr;
+ rt->mfc_expire = UPCALL_EXPIRE;
+ nexpire[hash]++;
+ for (i = 0; i < numvifs; i++)
+ rt->mfc_ttls[i] = 0;
+ rt->mfc_parent = -1;
/* link into table */
- hash = nethash_fc(rt->mfc_origin.s_addr, rt->mfc_mcastgrp.s_addr);
mb_rt->m_next = mfctable[hash];
mfctable[hash] = mb_rt;
mb_rt->m_act = NULL;
- }
-
- /* determine if q has overflowed */
- for (rte_m = mb_rt, hash = 0; rte_m->m_act; rte_m = rte_m->m_act)
- hash++;
-
- if (hash > MAX_UPQ) {
- mrtstat.mrts_upq_ovflw++;
- splx(s);
- return 0;
- }
+ rte_m = mb_rt;
+ } else {
+ /* determine if q has overflowed */
+ for (rte_m = mb_rt, npkts = 0; rte_m->m_act; rte_m = rte_m->m_act)
+ npkts++;
- /* add this packet and timing, ifp info to m_act */
- MGET(mb_ntry, M_DONTWAIT, MT_DATA);
- if (mb_ntry == NULL) {
- splx(s);
- return ENOBUFS;
+ if (npkts > MAX_UPQ) {
+ mrtstat.mrts_upq_ovflw++;
+ m_free(mb_ntry);
+ m_free(mb0);
+ splx(s);
+ return 0;
+ }
}
mb_ntry->m_act = NULL;
rte = mtod(mb_ntry, struct rtdetq *);
- mb0 = m_copy(m, 0, M_COPYALL);
- if (mb0 == NULL) {
- splx(s);
- return ENOBUFS;
- }
-
rte->m = mb0;
rte->ifp = ifp;
- rte->tunnel_src = tunnel_src;
- rte->imo = imo;
+#ifdef UPCALL_TIMING
+ rte->t = tp;
+#endif
- rte_m->m_act = mb_ntry;
+ /* Add this entry to the end of the queue */
+ rte_m->m_act = mb_ntry;
splx(s);
- if (hash == 0) {
- /*
- * Send message to routing daemon to install
- * a route into the kernel table
- */
- k_igmpsrc.sin_addr = ip->ip_src;
- k_igmpdst.sin_addr = ip->ip_dst;
-
- mm = m_copy(m, 0, M_COPYALL);
- if (mm == NULL) {
- splx(s);
- return ENOBUFS;
- }
-
- k_data = mtod(mm, struct ip *);
- k_data->ip_p = 0;
-
- mrtstat.mrts_upcalls++;
-
- rip_ip_input(mm, ip_mrouter, (struct sockaddr *)&k_igmpsrc);
-
- /* set timer to cleanup entry if upcall is lost */
- timeout(cleanup_cache, (caddr_t)mb_rt, 100);
- timeout_val++;
- }
-
return 0;
- }
+ }
}
#ifndef MROUTE_LKM
@@ -1142,99 +1302,160 @@ int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
* Clean up the cache entry if upcall is not serviced
*/
static void
-cleanup_cache(xmb_rt)
- void *xmb_rt;
+expire_upcalls(void *unused)
{
- struct mbuf *mb_rt = xmb_rt;
- struct mfc *rt;
- u_long hash;
- struct mbuf *prev_m0;
- struct mbuf *m0;
- struct mbuf *m;
+ struct mbuf *mb_rt, *m, **nptr;
struct rtdetq *rte;
+ struct mfc *mfc;
+ int i;
int s;
- rt = mtod(mb_rt, struct mfc *);
- hash = nethash_fc(rt->mfc_origin.s_addr, rt->mfc_mcastgrp.s_addr);
-
- if (mrtdebug)
- log(LOG_DEBUG, "ip_mforward: cleanup ipm %d h %d s %x g %x\n",
- ip_mrouter, hash, ntohl(rt->mfc_origin.s_addr),
- ntohl(rt->mfc_mcastgrp.s_addr));
-
- mrtstat.mrts_cache_cleanups++;
-
- /*
- * determine entry to be cleaned up in cache table
- */
s = splnet();
- for (prev_m0 = m0 = mfctable[hash]; m0; prev_m0 = m0, m0 = m0->m_next)
- if (m0 == mb_rt)
- break;
+ for (i = 0; i < MFCTBLSIZ; i++) {
+ if (nexpire[i] == 0)
+ continue;
+ nptr = &mfctable[i];
+ for (mb_rt = *nptr; mb_rt != NULL; mb_rt = *nptr) {
+ mfc = mtod(mb_rt, struct mfc *);
- /*
- * drop all the packets
- * free the mbuf with the pkt, if, timing info
- */
- while (mb_rt->m_act) {
- m = mb_rt->m_act;
- mb_rt->m_act = m->m_act;
+ /*
+ * Skip real cache entries
+ * Make sure it wasn't marked to not expire (shouldn't happen)
+ * If it expires now
+ */
+ if (mb_rt->m_act != NULL &&
+ mfc->mfc_expire != 0 &&
+ --mfc->mfc_expire == 0) {
+ if (mrtdebug & DEBUG_EXPIRE)
+ log(LOG_DEBUG, "expire_upcalls: expiring (%x %x)",
+ ntohl(mfc->mfc_origin.s_addr),
+ ntohl(mfc->mfc_mcastgrp.s_addr));
+ /*
+ * drop all the packets
+ * free the mbuf with the pkt, if, timing info
+ */
+ while (mb_rt->m_act) {
+ m = mb_rt->m_act;
+ mb_rt->m_act = m->m_act;
+
+ rte = mtod(m, struct rtdetq *);
+ m_freem(rte->m);
+ m_free(m);
+ }
+ ++mrtstat.mrts_cache_cleanups;
+ nexpire[i]--;
- rte = mtod(m, struct rtdetq *);
- m_freem(rte->m);
- m_free(m);
+ MFREE(mb_rt, *nptr);
+ } else {
+ nptr = &mb_rt->m_next;
+ }
+ }
}
-
- /*
- * Delete the entry from the cache
- */
- if (prev_m0 != m0) { /* if moved past head of list */
- MFREE(m0, prev_m0->m_next);
- } else /* delete head of list, it is in the table */
- mfctable[hash] = m_free(m0);
-
- timeout_val--;
splx(s);
+ timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
}
/*
* Packet forwarding routine once entry in the cache is made
*/
static int
-ip_mdq(m, ifp, tunnel_src, rt, imo)
+ip_mdq(m, ifp, rt, xmt_vif)
register struct mbuf *m;
register struct ifnet *ifp;
- register u_long tunnel_src;
register struct mfc *rt;
- register struct ip_moptions *imo;
+ register vifi_t xmt_vif;
{
register struct ip *ip = mtod(m, struct ip *);
register vifi_t vifi;
register struct vif *vifp;
+ register struct mbuf *tmp;
+ register int plen = ntohs(ip->ip_len);
+
+/*
+ * Macro to send packet on vif. Since RSVP packets don't get counted on
+ * input, they shouldn't get counted on output, so statistics keeping is
+ * seperate.
+ */
+#define MC_SEND(ip,vifp,m) { \
+ if ((vifp)->v_flags & VIFF_TUNNEL) \
+ encap_send((ip), (vifp), (m)); \
+ else \
+ phyint_send((ip), (vifp), (m)); \
+}
+
+ /*
+ * If xmt_vif is not -1, send on only the requested vif.
+ *
+ * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.)
+ */
+ if (xmt_vif < numvifs) {
+ MC_SEND(ip, viftable + xmt_vif, m);
+ return 1;
+ }
/*
* Don't forward if it didn't arrive from the parent vif for its origin.
- * Notes: v_ifp is zero for src route tunnels, multicast_decap_if
- * for encapsulated tunnels and a real ifnet for non-tunnels so
- * the first part of the if catches wrong physical interface or
- * tunnel type; v_rmt_addr is zero for non-tunneled packets so
- * the 2nd part catches both packets that arrive via a tunnel
- * that shouldn't and packets that arrive via the wrong tunnel.
*/
vifi = rt->mfc_parent;
- if (viftable[vifi].v_ifp != ifp ||
- (ifp == 0 && viftable[vifi].v_rmt_addr.s_addr != tunnel_src)) {
+ if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) {
/* came in the wrong interface */
- if (mrtdebug)
- log(LOG_DEBUG, "wrong if: ifp %x vifi %d\n",
- ifp, vifi);
+ if (mrtdebug & DEBUG_FORWARD)
+ log(LOG_DEBUG, "wrong if: ifp %x vifi %d vififp %x",
+ ifp, vifi, viftable[vifi].v_ifp);
++mrtstat.mrts_wrong_if;
- return (int)tunnel_src;
+ ++rt->mfc_wrong_if;
+ /*
+ * If we are doing PIM assert processing, and we are forwarding
+ * packets on this interface, and it is a broadcast medium
+ * interface (and not a tunnel), send a message to the routing daemon.
+ */
+ if (pim_assert && rt->mfc_ttls[vifi] &&
+ (ifp->if_flags & IFF_BROADCAST) &&
+ !(viftable[vifi].v_flags & VIFF_TUNNEL)) {
+ struct sockaddr_in k_igmpsrc;
+ struct mbuf *mm;
+ struct igmpmsg *im;
+ int hlen = ip->ip_hl << 2;
+ struct timeval now;
+ register u_long delta;
+
+ GET_TIME(now);
+
+ TV_DELTA(rt->mfc_last_assert, now, delta);
+
+ if (delta > ASSERT_MSG_TIME) {
+ mm = m_copy(m, 0, hlen);
+ if (mm && (M_HASCL(mm) || mm->m_len < hlen))
+ mm = m_pullup(mm, hlen);
+ if (mm == NULL) {
+ return ENOBUFS;
+ }
+
+ rt->mfc_last_assert = now;
+
+ im = mtod(mm, struct igmpmsg *);
+ im->im_msgtype = IGMPMSG_WRONGVIF;
+ im->im_mbz = 0;
+ im->im_vif = vifi;
+
+ k_igmpsrc.sin_addr = im->im_src;
+
+ socket_send(ip_mrouter, m, &k_igmpsrc);
+ }
+ }
+ return 0;
}
- /* increment the interface and s-g counters */
- viftable[vifi].v_pkt_in++;
+ /* If I sourced this packet, it counts as output, else it was input. */
+ if (ip->ip_src.s_addr == viftable[vifi].v_lcl_addr.s_addr) {
+ viftable[vifi].v_pkt_out++;
+ viftable[vifi].v_bytes_out += plen;
+ } else {
+ viftable[vifi].v_pkt_in++;
+ viftable[vifi].v_bytes_in += plen;
+ }
rt->mfc_pkt_cnt++;
+ rt->mfc_byte_cnt += plen;
/*
* For each vif, decide if a copy of the packet should be forwarded.
@@ -1242,40 +1463,26 @@ ip_mdq(m, ifp, tunnel_src, rt, imo)
* - the ttl exceeds the vif's threshold
* - there are group members downstream on interface
*/
-#define MC_SEND(ip,vifp,m) { \
- (vifp)->v_pkt_out++; \
- if ((vifp)->v_flags & VIFF_SRCRT) \
- srcrt_send((ip), (vifp), (m)); \
- else if ((vifp)->v_flags & VIFF_TUNNEL) \
- encap_send((ip), (vifp), (m)); \
- else \
- phyint_send((ip), (vifp), (m)); \
- }
-
-/* If no options or the imo_multicast_vif option is 0, don't do this part
- */
- if ((imo != NULL) &&
- (( vifi = imo->imo_multicast_vif - 1) < numvifs) /*&& (vifi>=0)*/)
- {
- MC_SEND(ip,viftable+vifi,m);
- return (1); /* make sure we are done: No more physical sends */
- }
-
for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++)
if ((rt->mfc_ttls[vifi] > 0) &&
- (ip->ip_ttl > rt->mfc_ttls[vifi]))
+ (ip->ip_ttl > rt->mfc_ttls[vifi])) {
+ vifp->v_pkt_out++;
+ vifp->v_bytes_out += plen;
MC_SEND(ip, vifp, m);
+ }
return 0;
}
-/* check if a vif number is legal/ok. This is used by ip_output, to export
- * numvifs there,
+/*
+ * check if a vif number is legal/ok. This is used by ip_output, to export
+ * numvifs there,
*/
int
X_legal_vif_num(vif)
int vif;
-{ if (vif>=0 && vif<=numvifs)
+{
+ if (vif >= 0 && vif < numvifs)
return(1);
else
return(0);
@@ -1285,6 +1492,23 @@ X_legal_vif_num(vif)
int (*legal_vif_num)(int) = X_legal_vif_num;
#endif
+/*
+ * Return the local address used by this vif
+ */
+u_long
+X_ip_mcast_src(vifi)
+ int vifi;
+{
+ if (vifi >= 0 && vifi < numvifs)
+ return viftable[vifi].v_lcl_addr.s_addr;
+ else
+ return INADDR_ANY;
+}
+
+#ifndef MROUTE_LKM
+u_long (*ip_mcast_src)(int) = X_ip_mcast_src;
+#endif
+
static void
phyint_send(ip, vifp, m)
struct ip *ip;
@@ -1292,19 +1516,19 @@ phyint_send(ip, vifp, m)
struct mbuf *m;
{
register struct mbuf *mb_copy;
- int hlen = ip->ip_hl << 2;
+ register int hlen = ip->ip_hl << 2;
register struct ip_moptions *imo;
- if ((mb_copy = m_copy(m, 0, M_COPYALL)) == NULL)
- return;
-
/*
- * Make sure the header isn't in an cluster, because the sharing
- * in clusters defeats the whole purpose of making the copy above.
+ * Make a new reference to the packet; make sure that
+ * the IP header is actually copied, not just referenced,
+ * so that ip_output() only scribbles on the copy.
*/
- mb_copy = m_pullup(mb_copy, hlen);
+ mb_copy = m_copy(m, 0, M_COPYALL);
+ if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < hlen))
+ mb_copy = m_pullup(mb_copy, hlen);
if (mb_copy == NULL)
- return;
+ return;
MALLOC(imo, struct ip_moptions *, sizeof *imo, M_IPMOPTS, M_NOWAIT);
if (imo == NULL) {
@@ -1315,6 +1539,7 @@ phyint_send(ip, vifp, m)
imo->imo_multicast_ifp = vifp->v_ifp;
imo->imo_multicast_ttl = ip->ip_ttl - 1;
imo->imo_multicast_loop = 1;
+ imo->imo_multicast_vif = -1;
if (vifp->v_rate_limit <= 0)
tbf_send_packet(vifp, mb_copy, imo);
@@ -1324,81 +1549,6 @@ phyint_send(ip, vifp, m)
}
static void
-srcrt_send(ip, vifp, m)
- struct ip *ip;
- struct vif *vifp;
- struct mbuf *m;
-{
- struct mbuf *mb_copy, *mb_opts;
- int hlen = ip->ip_hl << 2;
- register struct ip *ip_copy;
- u_char *cp;
-
- /*
- * Make sure that adding the tunnel options won't exceed the
- * maximum allowed number of option bytes.
- */
- if (ip->ip_hl > (60 - TUNNEL_LEN) >> 2) {
- mrtstat.mrts_cant_tunnel++;
- if (mrtdebug)
- log(LOG_DEBUG, "srcrt_send: no room for tunnel options, from %u\n",
- ntohl(ip->ip_src.s_addr));
- return;
- }
-
- if ((mb_copy = m_copy(m, 0, M_COPYALL)) == NULL)
- return;
-
- MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER);
- if (mb_opts == NULL) {
- m_freem(mb_copy);
- return;
- }
- /*
- * 'Delete' the base ip header from the mb_copy chain
- */
- mb_copy->m_len -= hlen;
- mb_copy->m_data += hlen;
- /*
- * Make mb_opts be the new head of the packet chain.
- * Any options of the packet were left in the old packet chain head
- */
- mb_opts->m_next = mb_copy;
- mb_opts->m_len = hlen + TUNNEL_LEN;
- mb_opts->m_data += MSIZE - mb_opts->m_len;
- mb_opts->m_pkthdr.len = mb_copy->m_pkthdr.len + TUNNEL_LEN;
- /*
- * Copy the base ip header from the mb_copy chain to the new head mbuf
- */
- ip_copy = mtod(mb_opts, struct ip *);
- bcopy((caddr_t)ip_copy, mtod(mb_opts, caddr_t), hlen);
- ip_copy->ip_ttl--;
- ip_copy->ip_dst = vifp->v_rmt_addr; /* remote tunnel end-point */
- /*
- * Adjust the ip header length to account for the tunnel options.
- */
- ip_copy->ip_hl += TUNNEL_LEN >> 2;
- ip_copy->ip_len += TUNNEL_LEN;
- /*
- * Add the NOP and LSRR after the base ip header
- */
- cp = mtod(mb_opts, u_char *) + IP_HDR_LEN;
- *cp++ = IPOPT_NOP;
- *cp++ = IPOPT_LSRR;
- *cp++ = 11; /* LSRR option length */
- *cp++ = 8; /* LSSR pointer to second element */
- *(u_long*)cp = vifp->v_lcl_addr.s_addr; /* local tunnel end-point */
- cp += 4;
- *(u_long*)cp = ip->ip_dst.s_addr; /* destination group */
-
- if (vifp->v_rate_limit <= 0)
- tbf_send_packet(vifp, mb_opts, 0);
- else
- tbf_control(vifp, mb_opts,
- mtod(mb_opts, struct ip *), ip_copy->ip_len, 0);
-}
-
-static void
encap_send(ip, vifp, m)
register struct ip *ip;
register struct vif *vifp;
@@ -1471,11 +1621,12 @@ encap_send(ip, vifp, m)
*/
void
#ifdef MROUTE_LKM
-X_multiencap_decap(m)
+X_ipip_input(m)
#else
-multiencap_decap(m)
+ipip_input(m, iphlen)
#endif
- register struct mbuf *m;
+ register struct mbuf *m;
+ int iphlen;
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
register struct ip *ip = mtod(m, struct ip *);
@@ -1484,9 +1635,9 @@ multiencap_decap(m)
register struct ifqueue *ifq;
register struct vif *vifp;
- if (ip->ip_p != ENCAP_PROTO) {
- rip_input(m);
- return;
+ if (!have_encap_tunnel) {
+ rip_input(m);
+ return;
}
/*
* dump the packet if it's not to a multicast destination or if
@@ -1502,7 +1653,7 @@ multiencap_decap(m)
}
if (ip->ip_src.s_addr != last_encap_src) {
register struct vif *vife;
-
+
vifp = viftable;
vife = vifp + numvifs;
last_encap_src = ip->ip_src.s_addr;
@@ -1520,7 +1671,7 @@ multiencap_decap(m)
mrtstat.mrts_cant_tunnel++; /*XXX*/
m_freem(m);
if (mrtdebug)
- log(LOG_DEBUG, "ip_mforward: no tunnel with %x\n",
+ log(LOG_DEBUG, "ip_mforward: no tunnel with %x",
ntohl(ip->ip_src.s_addr));
return;
}
@@ -1554,7 +1705,7 @@ multiencap_decap(m)
/*
* Token bucket filter module
*/
-void
+static void
tbf_control(vifp, m, ip, p_len, imo)
register struct vif *vifp;
register struct mbuf *m;
@@ -1564,7 +1715,7 @@ tbf_control(vifp, m, ip, p_len, imo)
{
tbf_update_tokens(vifp);
- /* if there are enough tokens,
+ /* if there are enough tokens,
* and the queue is empty,
* send this packet out
*/
@@ -1601,11 +1752,11 @@ tbf_control(vifp, m, ip, p_len, imo)
return;
}
-/*
+/*
* adds a packet to the queue at the interface
*/
-void
-tbf_queue(vifp, m, ip, imo)
+static void
+tbf_queue(vifp, m, ip, imo)
register struct vif *vifp;
register struct mbuf *m;
register struct ip *ip;
@@ -1627,10 +1778,10 @@ tbf_queue(vifp, m, ip, imo)
}
-/*
+/*
* processes the queue at the interface
*/
-void
+static void
tbf_process_q(vifp)
register struct vif *vifp;
{
@@ -1643,7 +1794,7 @@ tbf_process_q(vifp)
*/
while (vifp->v_tbf->q_len > 0) {
/* locate the first packet */
- pkt_1.pkt_len = ((qtable[index][0]).pkt_len);
+ pkt_1.pkt_len = (qtable[index][0]).pkt_len;
pkt_1.pkt_m = (qtable[index][0]).pkt_m;
pkt_1.pkt_ip = (qtable[index][0]).pkt_ip;
pkt_1.pkt_imo = (qtable[index][0]).pkt_imo;
@@ -1665,11 +1816,11 @@ tbf_process_q(vifp)
splx(s);
}
-/*
+/*
* removes the jth packet from the queue at the interface
*/
-void
-tbf_dequeue(vifp,j)
+static void
+tbf_dequeue(vifp,j)
register struct vif *vifp;
register int j;
{
@@ -1681,7 +1832,7 @@ tbf_dequeue(vifp,j)
qtable[index][i-1].pkt_len = qtable[index][i].pkt_len;
qtable[index][i-1].pkt_ip = qtable[index][i].pkt_ip;
qtable[index][i-1].pkt_imo = qtable[index][i].pkt_imo;
- }
+ }
qtable[index][i-1].pkt_m = NULL;
qtable[index][i-1].pkt_len = NULL;
qtable[index][i-1].pkt_ip = NULL;
@@ -1690,15 +1841,15 @@ tbf_dequeue(vifp,j)
vifp->v_tbf->q_len--;
if (tbfdebug > 1)
- log(LOG_DEBUG, "tbf_dequeue: vif# %d qlen %d\n",vifp-viftable, i-1);
+ log(LOG_DEBUG, "tbf_dequeue: vif# %d qlen %d",vifp-viftable, i-1);
}
-void
+static void
tbf_reprocess_q(xvifp)
void *xvifp;
{
register struct vif *vifp = xvifp;
- if (ip_mrouter == NULL)
+ if (ip_mrouter == NULL)
return;
tbf_update_tokens(vifp);
@@ -1713,7 +1864,7 @@ tbf_reprocess_q(xvifp)
* based on the precedence value and the priority obtained through
* a lookup table - not yet implemented accurately!
*/
-int
+static int
tbf_dq_sel(vifp, ip)
register struct vif *vifp;
register struct ip *ip;
@@ -1737,7 +1888,7 @@ tbf_dq_sel(vifp, ip)
return(0);
}
-void
+static void
tbf_send_packet(vifp, m, imo)
register struct vif *vifp;
register struct mbuf *m;
@@ -1746,13 +1897,7 @@ tbf_send_packet(vifp, m, imo)
int error;
int s = splnet();
- /* if source route tunnels */
- if (vifp->v_flags & VIFF_SRCRT) {
- error = ip_output(m, (struct mbuf *)0, (struct route *)0,
- IP_FORWARDING, imo);
- if (mrtdebug > 1)
- log(LOG_DEBUG, "srcrt_send on vif %d err %d\n", vifp-viftable, error);
- } else if (vifp->v_flags & VIFF_TUNNEL) {
+ if (vifp->v_flags & VIFF_TUNNEL) {
/* If tunnel options */
ip_output(m, (struct mbuf *)0, (struct route *)0,
IP_FORWARDING, imo);
@@ -1762,8 +1907,8 @@ tbf_send_packet(vifp, m, imo)
IP_FORWARDING, imo);
FREE(imo, M_IPMOPTS);
- if (mrtdebug > 1)
- log(LOG_DEBUG, "phyint_send on vif %d err %d\n", vifp-viftable, error);
+ if (mrtdebug & DEBUG_XMIT)
+ log(LOG_DEBUG, "phyint_send on vif %d err %d", vifp-viftable, error);
}
splx(s);
}
@@ -1772,7 +1917,7 @@ tbf_send_packet(vifp, m, imo)
* the elapsed time (between the last time and time now)
* in milliseconds & update the no. of tokens in the bucket
*/
-void
+static void
tbf_update_tokens(vifp)
register struct vif *vifp;
{
@@ -1800,54 +1945,255 @@ priority(vifp, ip)
register struct vif *vifp;
register struct ip *ip;
{
- register u_long graddr;
register int prio;
- /* temporary hack; will add general packet classifier some day */
-
- prio = 50; /* default priority */
+ /* temporary hack; may add general packet classifier some day */
- /* check for source route options and add option length to get dst */
- if (vifp->v_flags & VIFF_SRCRT)
- graddr = ntohl((ip+8)->ip_dst.s_addr);
- else
- graddr = ntohl(ip->ip_dst.s_addr);
-
- switch (graddr & 0xf) {
- case 0x0: break;
- case 0x1: if (graddr == 0xe0020001) prio = 65; /* MBone Audio */
- break;
- case 0x2: break;
- case 0x3: break;
- case 0x4: break;
- case 0x5: break;
- case 0x6: break;
- case 0x7: break;
- case 0x8: break;
- case 0x9: break;
- case 0xa: if (graddr == 0xe000010a) prio = 85; /* IETF Low Audio 1 */
- break;
- case 0xb: if (graddr == 0xe000010b) prio = 75; /* IETF Audio 1 */
- break;
- case 0xc: if (graddr == 0xe000010c) prio = 60; /* IETF Video 1 */
- break;
- case 0xd: if (graddr == 0xe000010d) prio = 80; /* IETF Low Audio 2 */
- break;
- case 0xe: if (graddr == 0xe000010e) prio = 70; /* IETF Audio 2 */
- break;
- case 0xf: if (graddr == 0xe000010f) prio = 55; /* IETF Video 2 */
- break;
+ /*
+ * The UDP port space is divided up into four priority ranges:
+ * [0, 16384) : unclassified - lowest priority
+ * [16384, 32768) : audio - highest priority
+ * [32768, 49152) : whiteboard - medium priority
+ * [49152, 65536) : video - low priority
+ */
+ if (ip->ip_p == IPPROTO_UDP) {
+ struct udphdr *udp = (struct udphdr *)(((char *)ip) + (ip->ip_hl << 2));
+ switch (ntohs(udp->uh_dport) & 0xc000) {
+ case 0x4000:
+ prio = 70;
+ break;
+ case 0x8000:
+ prio = 60;
+ break;
+ case 0xc000:
+ prio = 55;
+ break;
+ default:
+ prio = 50;
+ break;
+ }
+ if (tbfdebug > 1)
+ log(LOG_DEBUG, "port %x prio%d", ntohs(udp->uh_dport), prio);
+ } else {
+ prio = 50;
}
-
- if (tbfdebug > 1) log(LOG_DEBUG, "graddr%x prio%d\n", graddr, prio);
-
return prio;
}
/*
- * End of token bucket filter modifications
+ * End of token bucket filter modifications
*/
+int
+ip_rsvp_vif_init(so, m)
+ struct socket *so;
+ struct mbuf *m;
+{
+ int i;
+ register int s;
+
+ if (rsvpdebug)
+ printf("ip_rsvp_vif_init: so_type = %d, pr_protocol = %d\n",
+ so->so_type, so->so_proto->pr_protocol);
+
+ if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP)
+ return EOPNOTSUPP;
+
+ /* Check mbuf. */
+ if (m == NULL || m->m_len != sizeof(int)) {
+ return EINVAL;
+ }
+ i = *(mtod(m, int *));
+
+ if (rsvpdebug)
+ printf("ip_rsvp_vif_init: vif = %d rsvp_on = %d\n",i,rsvp_on);
+
+ s = splnet();
+
+ /* Check vif. */
+ if (!legal_vif_num(i)) {
+ splx(s);
+ return EADDRNOTAVAIL;
+ }
+
+ /* Check if socket is available. */
+ if (viftable[i].v_rsvpd != NULL) {
+ splx(s);
+ return EADDRINUSE;
+ }
+
+ viftable[i].v_rsvpd = so;
+ /* This may seem silly, but we need to be sure we don't over-increment
+ * the RSVP counter, in case something slips up.
+ */
+ if (!viftable[i].v_rsvp_on) {
+ viftable[i].v_rsvp_on = 1;
+ rsvp_on++;
+ }
+
+ splx(s);
+ return 0;
+}
+
+int
+ip_rsvp_vif_done(so, m)
+ struct socket *so;
+ struct mbuf *m;
+{
+ int i;
+ register int s;
+
+ if (rsvpdebug)
+ printf("ip_rsvp_vif_done: so_type = %d, pr_protocol = %d\n",
+ so->so_type, so->so_proto->pr_protocol);
+
+ if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP)
+ return EOPNOTSUPP;
+
+ /* Check mbuf. */
+ if (m == NULL || m->m_len != sizeof(int)) {
+ return EINVAL;
+ }
+ i = *(mtod(m, int *));
+
+ s = splnet();
+
+ /* Check vif. */
+ if (!legal_vif_num(i)) {
+ splx(s);
+ return EADDRNOTAVAIL;
+ }
+
+ if (rsvpdebug)
+ printf("ip_rsvp_vif_done: v_rsvpd = %x so = %x\n",
+ viftable[i].v_rsvpd, so);
+
+ viftable[i].v_rsvpd = NULL;
+ /* This may seem silly, but we need to be sure we don't over-decrement
+ * the RSVP counter, in case something slips up.
+ */
+ if (viftable[i].v_rsvp_on) {
+ viftable[i].v_rsvp_on = 0;
+ rsvp_on--;
+ }
+
+ splx(s);
+ return 0;
+}
+
+void
+ip_rsvp_force_done(so)
+ struct socket *so;
+{
+ int vifi;
+ register int s;
+
+ /* Don't bother if it is not the right type of socket. */
+ if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP)
+ return;
+
+ s = splnet();
+
+ /* The socket may be attached to more than one vif...this
+ * is perfectly legal.
+ */
+ for (vifi = 0; vifi < numvifs; vifi++) {
+ if (viftable[vifi].v_rsvpd == so) {
+ viftable[vifi].v_rsvpd = NULL;
+ /* This may seem silly, but we need to be sure we don't
+ * over-decrement the RSVP counter, in case something slips up.
+ */
+ if (viftable[vifi].v_rsvp_on) {
+ viftable[vifi].v_rsvp_on = 0;
+ rsvp_on--;
+ }
+ }
+ }
+
+ splx(s);
+ return;
+}
+
+void
+rsvp_input(m, ifp)
+ struct mbuf *m;
+ struct ifnet *ifp;
+{
+ int vifi;
+ register struct ip *ip = mtod(m, struct ip *);
+ static struct sockaddr_in rsvp_src = { AF_INET };
+ register int s;
+
+ if (rsvpdebug)
+ printf("rsvp_input: rsvp_on %d\n",rsvp_on);
+
+ /* Can still get packets with rsvp_on = 0 if there is a local member
+ * of the group to which the RSVP packet is addressed. But in this
+ * case we want to throw the packet away.
+ */
+ if (!rsvp_on) {
+ m_freem(m);
+ return;
+ }
+
+ /* If the old-style non-vif-associated socket is set, then use
+ * it and ignore the new ones.
+ */
+ if (ip_rsvpd != NULL) {
+ if (rsvpdebug)
+ printf("rsvp_input: Sending packet up old-style socket\n");
+ rip_input(m);
+ return;
+ }
+
+ s = splnet();
+
+ if (rsvpdebug)
+ printf("rsvp_input: check vifs\n");
+
+ /* Find which vif the packet arrived on. */
+ for (vifi = 0; vifi < numvifs; vifi++) {
+ if (viftable[vifi].v_ifp == ifp)
+ break;
+ }
+
+ if (vifi == numvifs) {
+ /* Can't find vif packet arrived on. Drop packet. */
+ if (rsvpdebug)
+ printf("rsvp_input: Can't find vif for packet...dropping it.\n");
+ m_freem(m);
+ splx(s);
+ return;
+ }
+
+ if (rsvpdebug)
+ printf("rsvp_input: check socket\n");
+
+ if (viftable[vifi].v_rsvpd == NULL) {
+ /* drop packet, since there is no specific socket for this
+ * interface */
+ if (rsvpdebug)
+ printf("rsvp_input: No socket defined for vif %d\n",vifi);
+ m_freem(m);
+ splx(s);
+ return;
+ }
+ rsvp_src.sin_addr = ip->ip_src;
+
+ if (rsvpdebug && m)
+ printf("rsvp_input: m->m_len = %d, sbspace() = %d\n",
+ m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv)));
+
+ if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0)
+ if (rsvpdebug)
+ printf("rsvp_input: Failed to append to socket\n");
+ else
+ if (rsvpdebug)
+ printf("rsvp_input: send packet up\n");
+
+ splx(s);
+}
+
#ifdef MROUTE_LKM
#include <sys/conf.h>
#include <sys/exec.h>
@@ -1884,7 +2230,7 @@ ip_mroute_mod_handle(struct lkm_table *lkmtp, int cmd)
old_mrt_ioctl = mrt_ioctl;
mrt_ioctl = X_mrt_ioctl;
old_proto4_input = inetsw[ip_protox[ENCAP_PROTO]].pr_input;
- inetsw[ip_protox[ENCAP_PROTO]].pr_input = X_multiencap_decap;
+ inetsw[ip_protox[ENCAP_PROTO]].pr_input = X_ipip_input;
old_legal_vif_num = legal_vif_num;
legal_vif_num = X_legal_vif_num;
ip_mrtproto = IGMP_DVMRP;
@@ -1921,5 +2267,3 @@ ip_mroute_mod(struct lkm_table *lkmtp, int cmd, int ver) {
#endif /* MROUTE_LKM */
#endif /* MROUTING */
-
-
diff --git a/sys/netinet/ip_mroute.h b/sys/netinet/ip_mroute.h
index 4c815e8..fd5ef37 100644
--- a/sys/netinet/ip_mroute.h
+++ b/sys/netinet/ip_mroute.h
@@ -42,28 +42,29 @@
#define _NETINET_IP_MROUTE_H_
/*
- * Definitions for the kernel part of DVMRP,
- * a Distance-Vector Multicast Routing Protocol.
- * (See RFC-1075.)
+ * Definitions for IP multicast forwarding.
*
* Written by David Waitzman, BBN Labs, August 1988.
* Modified by Steve Deering, Stanford, February 1989.
* Modified by Ajit Thyagarajan, PARC, August 1993.
* Modified by Ajit Thyagarajan, PARC, August 1994.
*
- * MROUTING 1.5
+ * MROUTING Revision: 3.3.1.3
*/
/*
- * DVMRP-specific setsockopt commands.
+ * Multicast Routing set/getsockopt commands.
*/
-#define DVMRP_INIT 100 /* initialize forwarder */
-#define DVMRP_DONE 101 /* shut down forwarder */
-#define DVMRP_ADD_VIF 102 /* create virtual interface */
-#define DVMRP_DEL_VIF 103 /* delete virtual interface */
-#define DVMRP_ADD_MFC 104 /* insert forwarding cache entry */
-#define DVMRP_DEL_MFC 105 /* delete forwarding cache entry */
+#define MRT_INIT 100 /* initialize forwarder */
+#define MRT_DONE 101 /* shut down forwarder */
+#define MRT_ADD_VIF 102 /* create virtual interface */
+#define MRT_DEL_VIF 103 /* delete virtual interface */
+#define MRT_ADD_MFC 104 /* insert forwarding cache entry */
+#define MRT_DEL_MFC 105 /* delete forwarding cache entry */
+#define MRT_VERSION 106 /* get kernel version number */
+#define MRT_ASSERT 107 /* enable PIM assert processing */
+
#define GET_TIME(t) microtime(&t)
@@ -73,6 +74,7 @@
#define MAXVIFS 32
typedef u_long vifbitmap_t;
typedef u_short vifi_t; /* type of a vif index */
+#define ALL_VIFS (vifi_t)-1
#define VIFM_SET(n, m) ((m) |= (1 << (n)))
#define VIFM_CLR(n, m) ((m) &= ~(1 << (n)))
@@ -83,59 +85,33 @@ typedef u_short vifi_t; /* type of a vif index */
/*
- * Argument structure for DVMRP_ADD_VIF.
- * (DVMRP_DEL_VIF takes a single vifi_t argument.)
+ * Argument structure for MRT_ADD_VIF.
+ * (MRT_DEL_VIF takes a single vifi_t argument.)
*/
struct vifctl {
- vifi_t vifc_vifi; /* the index of the vif to be added */
- u_char vifc_flags; /* VIFF_ flags defined below */
- u_char vifc_threshold; /* min ttl required to forward on vif */
- u_int vifc_rate_limit; /* max tate */
+ vifi_t vifc_vifi; /* the index of the vif to be added */
+ u_char vifc_flags; /* VIFF_ flags defined below */
+ u_char vifc_threshold; /* min ttl required to forward on vif */
+ u_int vifc_rate_limit; /* max rate */
struct in_addr vifc_lcl_addr; /* local interface address */
struct in_addr vifc_rmt_addr; /* remote address (tunnels only) */
};
#define VIFF_TUNNEL 0x1 /* vif represents a tunnel end-point */
-#define VIFF_SRCRT 0x2 /* tunnel uses IP source routing */
+#define VIFF_SRCRT 0x2 /* tunnel uses IP source routing */
/*
- * Argument structure for DVMRP_ADD_MFC
+ * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC
* (mfcc_tos to be added at a future point)
*/
struct mfcctl {
- struct in_addr mfcc_origin; /* subnet origin of mcasts */
+ struct in_addr mfcc_origin; /* ip origin of mcasts */
struct in_addr mfcc_mcastgrp; /* multicast group associated*/
- struct in_addr mfcc_originmask; /* subnet mask for origin */
vifi_t mfcc_parent; /* incoming vif */
u_char mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */
};
/*
- * Argument structure for DVMRP_DEL_MFC
- */
-struct delmfcctl {
- struct in_addr mfcc_origin; /* subnet origin of multicasts */
- struct in_addr mfcc_mcastgrp; /* multicast group assoc. w/ origin */
-};
-
-/*
- * Argument structure used by RSVP daemon to get vif information
- */
-struct vif_req {
- u_char v_flags; /* VIFF_ flags defined above */
- u_char v_threshold; /* min ttl required to forward on vif */
- struct in_addr v_lcl_addr; /* local interface address */
- struct in_addr v_rmt_addr;
- char v_if_name[IFNAMSIZ]; /* if name */
-};
-
-struct vif_conf {
- u_int vifc_len;
- u_int vifc_num;
- struct vif_req *vifc_req;
-};
-
-/*
* The kernel's multicast routing statistics.
*/
struct mrtstat {
@@ -151,6 +127,7 @@ struct mrtstat {
u_long mrts_drop_sel; /* pkts dropped selectively */
u_long mrts_q_overflow; /* pkts dropped - Q overflow */
u_long mrts_pkt2large; /* pkts dropped - size > BKT SIZE */
+ u_long mrts_upq_sockfull; /* upcalls dropped - socket full */
};
/*
@@ -159,21 +136,28 @@ struct mrtstat {
struct sioc_sg_req {
struct in_addr src;
struct in_addr grp;
- u_long count;
+ u_long pktcnt;
+ u_long bytecnt;
+ u_long wrong_if;
};
/*
* Argument structure used by mrouted to get vif pkt counts
*/
struct sioc_vif_req {
- vifi_t vifi;
- u_long icount;
- u_long ocount;
+ vifi_t vifi; /* vif number */
+ u_long icount; /* Input packet count on vif */
+ u_long ocount; /* Output packet count on vif */
+ u_long ibytes; /* Input byte count on vif */
+ u_long obytes; /* Output byte count on vif */
};
-
+
#ifdef KERNEL
+/*
+ * The kernel's virtual-interface structure.
+ */
struct vif {
u_char v_flags; /* VIFF_ flags defined above */
u_char v_threshold; /* min ttl required to forward on vif*/
@@ -184,30 +168,56 @@ struct vif {
struct ifnet *v_ifp; /* pointer to interface */
u_long v_pkt_in; /* # pkts in on interface */
u_long v_pkt_out; /* # pkts out on interface */
+ u_long v_bytes_in; /* # bytes in on interface */
+ u_long v_bytes_out; /* # bytes out on interface */
+ struct route v_route; /* cached route if this is a tunnel */
+ u_int v_rsvp_on; /* RSVP listening on this vif */
+ struct socket *v_rsvpd; /* RSVP daemon socket */
};
/*
- * The kernel's multicast forwarding cache entry structure
- * (A field for the type of service (mfc_tos) is to be added
+ * The kernel's multicast forwarding cache entry structure
+ * (A field for the type of service (mfc_tos) is to be added
* at a future point)
*/
struct mfc {
- struct in_addr mfc_origin; /* subnet origin of mcasts */
+ struct in_addr mfc_origin; /* IP origin of mcasts */
struct in_addr mfc_mcastgrp; /* multicast group associated*/
- struct in_addr mfc_originmask; /* subnet mask for origin */
vifi_t mfc_parent; /* incoming vif */
u_char mfc_ttls[MAXVIFS]; /* forwarding ttls on vifs */
u_long mfc_pkt_cnt; /* pkt count for src-grp */
+ u_long mfc_byte_cnt; /* byte count for src-grp */
+ u_long mfc_wrong_if; /* wrong if for src-grp */
+ int mfc_expire; /* time to clean entry up */
+ struct timeval mfc_last_assert; /* last time I sent an assert*/
+};
+
+/*
+ * Struct used to communicate from kernel to multicast router
+ * note the convenient similarity to an IP packet
+ */
+struct igmpmsg {
+ u_long unused1;
+ u_long unused2;
+ u_char im_msgtype; /* what type of message */
+#define IGMPMSG_NOCACHE 1
+#define IGMPMSG_WRONGVIF 2
+ u_char im_mbz; /* must be zero */
+ u_char im_vif; /* vif rec'd on */
+ u_char unused3;
+ struct in_addr im_src, im_dst;
};
/*
* Argument structure used for pkt info. while upcall is made
*/
struct rtdetq {
- struct mbuf *m;
- struct ifnet *ifp;
- u_long tunnel_src;
- struct ip_moptions *imo;
+ struct mbuf *m; /* A copy of the packet */
+ struct ifnet *ifp; /* Interface pkt came in on */
+ vifi_t xmt_vif; /* Saved copy of imo_multicast_vif */
+#ifdef UPCALL_TIMING
+ struct timeval t; /* Timestamp */
+#endif /* UPCALL_TIMING */
};
#define MFCTBLSIZ 256
@@ -220,7 +230,7 @@ struct rtdetq {
#define MAX_UPQ 4 /* max. no of pkts in upcall Q */
/*
- * Token Bucket filter code
+ * Token Bucket filter code
*/
#define MAX_BKT_SIZE 10000 /* 10K bytes size */
#define MAXQSIZE 10 /* max # of pkts in queue */
@@ -228,7 +238,7 @@ struct rtdetq {
/*
* queue structure at each vif
*/
-struct pkt_queue
+struct pkt_queue
{
u_long pkt_len; /* length of packet in queue */
struct mbuf *pkt_m; /* pointer to packet mbuf */
@@ -246,7 +256,8 @@ struct tbf
u_long q_len; /* length of queue at this vif */
};
-extern int (*ip_mrouter_cmd) __P((int, struct socket *, struct mbuf *));
+extern int (*ip_mrouter_set) __P((int, struct socket *, struct mbuf *));
+extern int (*ip_mrouter_get) __P((int, struct socket *, struct mbuf **));
extern int (*ip_mrouter_done) __P((void));
extern int (*mrt_ioctl) __P((int, caddr_t, struct proc *));
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 8e6fb56..45c21cc 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -188,15 +188,20 @@ ip_output(m0, opt, ro, flags, imo)
ip->ip_ttl = imo->imo_multicast_ttl;
if (imo->imo_multicast_ifp != NULL)
ifp = imo->imo_multicast_ifp;
+ if (imo->imo_multicast_vif != -1)
+ ip->ip_src.s_addr =
+ ip_mcast_src(imo->imo_multicast_vif);
} else
ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
/*
* Confirm that the outgoing interface supports multicast.
*/
- if ((ifp->if_flags & IFF_MULTICAST) == 0) {
- ipstat.ips_noroute++;
- error = ENETUNREACH;
- goto bad;
+ if ((imo == NULL) || (imo->imo_multicast_vif == -1)) {
+ if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+ ipstat.ips_noroute++;
+ error = ENETUNREACH;
+ goto bad;
+ }
}
/*
* If source address not specified yet, use address
@@ -805,7 +810,7 @@ ip_setmoptions(optname, imop, m)
return (ENOBUFS);
*imop = imo;
imo->imo_multicast_ifp = NULL;
- imo->imo_multicast_vif = 0;
+ imo->imo_multicast_vif = -1;
imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
imo->imo_num_memberships = 0;
@@ -823,7 +828,7 @@ ip_setmoptions(optname, imop, m)
break;
}
i = *(mtod(m, int *));
- if (!legal_vif_num(i)) {
+ if (!legal_vif_num(i) && (i != -1)) {
error = EINVAL;
break;
}
@@ -907,7 +912,7 @@ ip_setmoptions(optname, imop, m)
* the route to the given multicast address.
*/
if (mreq->imr_interface.s_addr == INADDR_ANY) {
- ro.ro_rt = NULL;
+ bzero((caddr_t)&ro, sizeof(ro));
dst = (struct sockaddr_in *)&ro.ro_dst;
dst->sin_len = sizeof(*dst);
dst->sin_family = AF_INET;
@@ -1036,7 +1041,7 @@ ip_setmoptions(optname, imop, m)
* If all options have default values, no need to keep the mbuf.
*/
if (imo->imo_multicast_ifp == NULL &&
- imo->imo_multicast_vif == 0 &&
+ imo->imo_multicast_vif == -1 &&
imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
imo->imo_num_memberships == 0) {
@@ -1065,11 +1070,11 @@ ip_getmoptions(optname, imo, mp)
switch (optname) {
- case IP_MULTICAST_VIF:
+ case IP_MULTICAST_VIF:
if (imo != NULL)
*(mtod(*mp, int *)) = imo->imo_multicast_vif;
else
- *(mtod(*mp, int *)) = 7890;
+ *(mtod(*mp, int *)) = -1;
(*mp)->m_len = sizeof(int);
return(0);
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 73bd43d..3bfd8ff 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -71,11 +71,11 @@ struct ipq {
* Note: ipf_next must be at same offset as ipq_next above
*/
struct ipasfrag {
-#if BYTE_ORDER == LITTLE_ENDIAN
+#if BYTE_ORDER == LITTLE_ENDIAN
u_char ip_hl:4,
ip_v:4;
#endif
-#if BYTE_ORDER == BIG_ENDIAN
+#if BYTE_ORDER == BIG_ENDIAN
u_char ip_v:4,
ip_hl:4;
#endif
@@ -111,11 +111,11 @@ struct ipoption {
*/
struct ip_moptions {
struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */
- u_long imo_multicast_vif; /* vif num outgoing multicasts */
u_char imo_multicast_ttl; /* TTL for outgoing multicasts */
u_char imo_multicast_loop; /* 1 => hear sends if a member */
u_short imo_num_memberships; /* no. memberships this socket */
struct in_multi *imo_membership[IP_MAX_MEMBERSHIPS];
+ u_long imo_multicast_vif; /* vif num outgoing multicasts */
};
struct ipstat {
@@ -160,6 +160,7 @@ extern u_char ip_protox[];
extern struct socket *ip_rsvpd; /* reservation protocol daemon */
extern struct socket *ip_mrouter; /* multicast routing daemon */
extern int (*legal_vif_num) __P((int));
+extern u_long (*ip_mcast_src) __P((int));
int ip_ctloutput __P((int, struct socket *, int, int, struct mbuf **));
void ip_deq __P((struct ipasfrag *));
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 89697a0..133b6ac 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -136,27 +136,6 @@ rip_input(m)
}
}
-void rip_ip_input(mm, ip_mrouter, src)
- struct mbuf *mm;
- register struct socket *ip_mrouter;
- struct sockaddr *src;
-{
- if (ip_mrouter)
- {
- if (sbappendaddr(&ip_mrouter->so_rcv, src,
- mm, (struct mbuf *) 0) == 0)
- m_freem(mm);
- else
- sorwakeup(ip_mrouter);
- }
- else
- {
- m_freem(mm);
- ipstat.ips_noproto++;
- ipstat.ips_delivered--;
- }
-}
-
/*
* Generate IP header and pass packet to ip_output.
* Tack on options user may have setup with control call.
@@ -249,7 +228,7 @@ rip_ctloutput(op, so, level, optname, m)
}
if (op == PRCO_SETOPT) {
- error=(*ip_fw_ctl_ptr)(optname, *m);
+ error=(*ip_fw_ctl_ptr)(optname, *m);
if (*m)
(void)m_free(*m);
}
@@ -261,13 +240,13 @@ rip_ctloutput(op, so, level, optname, m)
case IP_ACCT_ADD:
case IP_ACCT_CLR:
case IP_ACCT_FLUSH:
- case IP_ACCT_ZERO:
+ case IP_ACCT_ZERO:
if (ip_acct_ctl_ptr==NULL) {
if (*m)
(void)m_free(*m);
return(EINVAL);
}
-
+
if (op == PRCO_SETOPT) {
error=(*ip_acct_ctl_ptr)(optname, *m);
if (*m)
@@ -285,16 +264,26 @@ rip_ctloutput(op, so, level, optname, m)
return ip_rsvp_done();
break;
- case DVMRP_INIT:
- case DVMRP_DONE:
- case DVMRP_ADD_VIF:
- case DVMRP_DEL_VIF:
- case DVMRP_ADD_MFC:
- case DVMRP_DEL_MFC:
+ case IP_RSVP_VIF_ON:
+ return ip_rsvp_vif_init(so, *m);
+
+ case IP_RSVP_VIF_OFF:
+ return ip_rsvp_vif_done(so, *m);
+
+ case MRT_INIT:
+ case MRT_DONE:
+ case MRT_ADD_VIF:
+ case MRT_DEL_VIF:
+ case MRT_ADD_MFC:
+ case MRT_DEL_MFC:
+ case MRT_VERSION:
+ case MRT_ASSERT:
if (op == PRCO_SETOPT) {
- error = ip_mrouter_cmd(optname, so, *m);
+ error = ip_mrouter_set(optname, so, *m);
if (*m)
(void)m_free(*m);
+ } else if (op == PRCO_GETOPT) {
+ error = ip_mrouter_get(optname, so, m);
} else
error = EINVAL;
return (error);
OpenPOWER on IntegriCloud