summaryrefslogtreecommitdiffstats
path: root/usr.sbin/mrouted/igmp.c
diff options
context:
space:
mode:
authorfenner <fenner@FreeBSD.org>1996-11-11 03:50:15 +0000
committerfenner <fenner@FreeBSD.org>1996-11-11 03:50:15 +0000
commiteb4f38517ab6b3334eae830239bce13bc11365d4 (patch)
tree165f9cfd99d55b06f466b5dad237613485ce8624 /usr.sbin/mrouted/igmp.c
parent1a38735f41eb97c0d485559ee3465c527c73c0d4 (diff)
downloadFreeBSD-src-eb4f38517ab6b3334eae830239bce13bc11365d4.zip
FreeBSD-src-eb4f38517ab6b3334eae830239bce13bc11365d4.tar.gz
Update to the unreleased mrouted 3.8a . This includes a minor
endian-ness fix, Router Alert options on IGMP messages, and a new keyword, "advert_metric", for fine-tuning tunnel metrics. This also includes a new mtrace, which is also unreleased but builds significantly on the experiences of users' troubles with using and understanding mtrace in release 3.8 . (unreleased does not, of course, mean untested!) This is a candidate for both 2.2 and 2.1.6 .
Diffstat (limited to 'usr.sbin/mrouted/igmp.c')
-rw-r--r--usr.sbin/mrouted/igmp.c122
1 files changed, 116 insertions, 6 deletions
diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c
index bbcd707..f1ded9a 100644
--- a/usr.sbin/mrouted/igmp.c
+++ b/usr.sbin/mrouted/igmp.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: igmp.c,v 1.9 1996/01/06 21:09:44 peter Exp $
+ * $Id: igmp.c,v 3.8.1.1 1996/08/09 22:49:12 fenner Exp $
*/
@@ -26,6 +26,23 @@ u_int32 dvmrp_group; /* DVMRP grp addr in net order */
u_int32 dvmrp_genid; /* IGMP generation id */
/*
+ * Private variables
+ */
+static char router_alert[4]; /* Router Alert IP Option */
+#ifndef IPOPT_RA
+#define IPOPT_RA 148
+#endif
+#ifdef SUNOS5
+static char no_op[4]; /* Null IP Option */
+static int ip_addlen = 0; /* Workaround for Option bug #2*/
+#endif
+#define SEND_RA(x) (((x) == IGMP_MEMBERSHIP_QUERY) || \
+ ((x) == IGMP_V1_MEMBERSHIP_REPORT) || \
+ ((x) == IGMP_V2_MEMBERSHIP_REPORT) || \
+ ((x) == IGMP_V2_LEAVE_GROUP) || \
+ ((x) == IGMP_MTRACE))
+
+/*
* Local function definitions.
*/
/* u_char promoted to u_int */
@@ -40,6 +57,9 @@ void
init_igmp()
{
struct ip *ip;
+#ifdef SUNOS5
+ u_int32 localhost = htonl(0x7f000001);
+#endif
recv_buf = malloc(RECV_BUF_SIZE);
send_buf = malloc(RECV_BUF_SIZE);
@@ -63,6 +83,67 @@ init_igmp()
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
dvmrp_group = htonl(INADDR_DVMRP_GROUP);
allrtrs_group = htonl(INADDR_ALLRTRS_GROUP);
+
+ router_alert[0] = IPOPT_RA; /* Router Alert */
+ router_alert[1] = 4; /* 4 bytes */
+ router_alert[2] = 0;
+ router_alert[3] = 0;
+
+#ifdef SUNOS5
+ no_op[0] = IPOPT_NOP;
+ no_op[1] = IPOPT_NOP;
+ no_op[2] = IPOPT_NOP;
+ no_op[3] = IPOPT_NOP;
+
+ setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, no_op, sizeof(no_op));
+ /*
+ * Check if the kernel adds the options length to the packet
+ * length. Send myself an IGMP packet of type 0 (illegal),
+ * with 4 IPOPT_NOP options, my PID (for collision detection)
+ * and 4 bytes of zero (so that the checksum works whether
+ * the 4 bytes of zero get truncated or not).
+ */
+ bzero(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN, 8);
+ *(int *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN) = getpid();
+ send_igmp(localhost, localhost, 0, 0, 0, 8);
+ while (1) {
+ int recvlen, dummy = 0;
+
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+ 0, NULL, &dummy);
+ /* 8 == 4 bytes of options and 4 bytes of PID */
+ if (recvlen >= MIN_IP_HEADER_LEN + IGMP_MINLEN + 8) {
+ struct ip *ip = (struct ip *)recv_buf;
+ struct igmp *igmp;
+ int *p;
+
+ if (ip->ip_hl != 6 ||
+ ip->ip_p != IPPROTO_IGMP ||
+ ip->ip_src.s_addr != localhost ||
+ ip->ip_dst.s_addr != localhost)
+ continue;
+
+ igmp = (struct igmp *)(recv_buf + (ip->ip_hl << 2));
+ if (igmp->igmp_group.s_addr != 0)
+ continue;
+ if (igmp->igmp_type != 0 || igmp->igmp_code != 0)
+ continue;
+
+ p = (int *)((char *)igmp + IGMP_MINLEN);
+ if (*p != getpid())
+ continue;
+
+ if (ip->ip_len == IGMP_MINLEN + 4)
+ ip_addlen = 4;
+ else if (ip->ip_len == IGMP_MINLEN + 8)
+ ip_addlen = 0;
+ else
+ log(LOG_ERR, 0, "while checking for Solaris bug: Sent %d bytes and got back %d!", IGMP_MINLEN + 8, ip->ip_len);
+
+ break;
+ }
+ }
+#endif
}
#define PIM_QUERY 0
@@ -80,8 +161,8 @@ packet_kind(type, code)
{
switch (type) {
case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
- case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
- case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new member report ";
+ case IGMP_HOST_MEMBERSHIP_REPORT: return "V1 member report ";
+ case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "V2 member report ";
case IGMP_HOST_LEAVE_MESSAGE: return "leave message ";
case IGMP_DVMRP:
switch (code) {
@@ -310,12 +391,19 @@ send_igmp(src, dst, type, code, group, datalen)
struct sockaddr_in sdst;
struct ip *ip;
struct igmp *igmp;
- int setloop;
+ int setloop = 0;
+ static int raset = 0;
+ int sendra = 0;
+ int sendlen;
ip = (struct ip *)send_buf;
ip->ip_src.s_addr = src;
ip->ip_dst.s_addr = dst;
ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
+ sendlen = ip->ip_len;
+#ifdef SUNOS5
+ ip->ip_len += ip_addlen;
+#endif
igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
igmp->igmp_type = type;
@@ -331,6 +419,27 @@ send_igmp(src, dst, type, code, group, datalen)
setloop = 1;
k_set_loop(TRUE);
}
+ if (SEND_RA(type))
+ sendra = 1;
+ }
+
+ if (sendra && !raset) {
+ setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
+ router_alert, sizeof(router_alert));
+ raset = 1;
+ } else if (!sendra && raset) {
+#ifdef SUNOS5
+ /*
+ * SunOS5 < 5.6 cannot properly reset the IP_OPTIONS "socket"
+ * option. Instead, set up a string of 4 no-op's.
+ */
+ setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
+ no_op, sizeof(no_op));
+#else
+ setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
+ NULL, 0);
+#endif
+ raset = 0;
}
bzero(&sdst, sizeof(sdst));
@@ -339,7 +448,7 @@ send_igmp(src, dst, type, code, group, datalen)
sdst.sin_len = sizeof(sdst);
#endif
sdst.sin_addr.s_addr = dst;
- if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
+ if (sendto(igmp_socket, send_buf, sendlen, 0,
(struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
if (errno == ENETDOWN)
check_vif_state();
@@ -353,5 +462,6 @@ send_igmp(src, dst, type, code, group, datalen)
k_set_loop(FALSE);
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
- packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
+ packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
+ inet_fmt(src, s1), inet_fmt(dst, s2));
}
OpenPOWER on IntegriCloud