1 /* 2 * The mrouted program is covered by the license in the accompanying file 3 * named "LICENSE". Use of the mrouted program represents acceptance of 4 * the terms and conditions listed in that file. 5 * 6 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 * Leland Stanford Junior University. 8 * 9 * 10 * from: Id: igmp.c,v 1.5 1993/06/23 18:47:17 pavel Exp 11 * $Id: igmp.c,v 1.2 1994/06/09 16:05:28 brezak Exp $ 12 */ 13 14 #ifndef lint 15 static char rcsid[] = "$Id: igmp.c,v 1.2 1994/06/09 16:05:28 brezak Exp $"; 16 #endif 17 18 #include "defs.h" 19 20 21 /* 22 * Exported variables. 23 */ 24 char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */ 25 char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */ 26 int igmp_socket; /* socket for all network I/O */ 27 u_long allhosts_group; /* allhosts addr in net order */ 28 u_long dvmrp_group; /* DVMRP grp addr in net order */ 29 30 31 /* 32 * Open and initialize the igmp socket, and fill in the non-changing 33 * IP header fields in the output packet buffer. 34 */ 35 void init_igmp() 36 { 37 struct ip *ip; 38 39 if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) 40 log(LOG_ERR, errno, "IGMP socket"); 41 42 k_hdr_include(TRUE); /* include IP header when sending */ 43 k_set_rcvbuf(48*1024); /* lots of input buffering */ 44 k_set_ttl(1); /* restrict multicasts to one hop */ 45 k_set_loop(FALSE); /* disable multicast loopback */ 46 47 ip = (struct ip *)send_buf; 48 ip->ip_tos = 0; 49 ip->ip_off = 0; 50 ip->ip_v = IPVERSION; 51 ip->ip_p = IPPROTO_IGMP; 52 ip->ip_ttl = MAXTTL; /* applies to unicasts only */ 53 ip->ip_hl = (MIN_IP_HEADER_LEN >> 2); 54 55 allhosts_group = htonl(INADDR_ALLHOSTS_GROUP); 56 dvmrp_group = htonl(INADDR_DVMRP_GROUP); 57 } 58 59 static char *packet_kind(type, code) 60 u_char type, code; 61 { 62 switch (type) { 63 case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query "; 64 case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report "; 65 case IGMP_DVMRP: 66 switch (code) { 67 case DVMRP_PROBE: return "neighbor probe "; 68 case DVMRP_REPORT: return "route report "; 69 case DVMRP_ASK_NEIGHBORS: return "neighbor request "; 70 case DVMRP_NEIGHBORS: return "neighbor list "; 71 case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2"; 72 case DVMRP_NEIGHBORS2: return "neighbor list 2 "; 73 default: return "unknown DVMRP msg "; 74 } 75 default: return "unknown IGMP msg "; 76 } 77 } 78 79 /* 80 * Process a newly received IGMP packet that is sitting in the input 81 * packet buffer. 82 */ 83 void accept_igmp(recvlen) 84 int recvlen; 85 { 86 register vifi_t vifi; 87 register u_long src, dst, group; 88 struct ip *ip; 89 struct igmp *igmp; 90 int ipdatalen, iphdrlen, igmpdatalen; 91 92 if (recvlen < sizeof(struct ip)) { 93 log(LOG_WARNING, 0, 94 "received packet too short (%u bytes) for IP header", recvlen); 95 return; 96 } 97 98 ip = (struct ip *)recv_buf; 99 src = ip->ip_src.s_addr; 100 dst = ip->ip_dst.s_addr; 101 iphdrlen = ip->ip_hl << 2; 102 ipdatalen = ip->ip_len; 103 if (iphdrlen + ipdatalen != recvlen) { 104 log(LOG_WARNING, 0, 105 "received packet shorter (%u bytes) than hdr+data length (%u+%u)", 106 recvlen, iphdrlen, ipdatalen); 107 return; 108 } 109 110 igmp = (struct igmp *)(recv_buf + iphdrlen); 111 group = igmp->igmp_group.s_addr; 112 igmpdatalen = ipdatalen - IGMP_MINLEN; 113 if (igmpdatalen < 0) { 114 log(LOG_WARNING, 0, 115 "received IP data field too short (%u bytes) for IGMP, from %s", 116 ipdatalen, inet_fmt(src, s1)); 117 return; 118 } 119 120 log(LOG_DEBUG, 0, "RECV %s from %-15s to %s", 121 packet_kind(igmp->igmp_type, igmp->igmp_code), 122 inet_fmt(src, s1), inet_fmt(dst, s2)); 123 124 switch (igmp->igmp_type) { 125 126 case IGMP_HOST_MEMBERSHIP_QUERY: 127 return; /* Answered automatically by the kernel. */ 128 129 case IGMP_HOST_MEMBERSHIP_REPORT: 130 accept_group_report(src, dst, group); 131 return; 132 133 case IGMP_DVMRP: 134 switch (igmp->igmp_code) { 135 136 case DVMRP_PROBE: 137 accept_probe(src, dst); 138 return; 139 140 case DVMRP_REPORT: 141 accept_report(src, dst, 142 (char *)(igmp+1), igmpdatalen); 143 return; 144 145 case DVMRP_ASK_NEIGHBORS: 146 accept_neighbor_request(src, dst); 147 return; 148 149 case DVMRP_ASK_NEIGHBORS2: 150 accept_neighbor_request2(src, dst); 151 return; 152 153 case DVMRP_NEIGHBORS: 154 accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen, 155 group); 156 return; 157 158 case DVMRP_NEIGHBORS2: 159 accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen, 160 group); 161 return; 162 163 default: 164 log(LOG_INFO, 0, 165 "ignoring unknown DVMRP message code %u from %s to %s", 166 igmp->igmp_code, inet_fmt(src, s1), 167 inet_fmt(dst, s2)); 168 return; 169 } 170 171 default: 172 log(LOG_INFO, 0, 173 "ignoring unknown IGMP message type %u from %s to %s", 174 igmp->igmp_type, inet_fmt(src, s1), 175 inet_fmt(dst, s2)); 176 return; 177 } 178 } 179 180 181 /* 182 * Construct an IGMP message in the output packet buffer. The caller may 183 * have already placed data in that buffer, of length 'datalen'. Then send 184 * the message from the interface with IP address 'src' to destination 'dst'. 185 */ 186 void send_igmp(src, dst, type, code, group, datalen) 187 u_long src, dst; 188 int type, code; 189 u_long group; 190 int datalen; 191 { 192 static struct sockaddr_in sdst = {AF_INET}; 193 struct ip *ip; 194 struct igmp *igmp; 195 196 ip = (struct ip *)send_buf; 197 ip->ip_src.s_addr = src; 198 ip->ip_dst.s_addr = dst; 199 ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; 200 201 igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN); 202 igmp->igmp_type = type; 203 igmp->igmp_code = code; 204 igmp->igmp_group.s_addr = group; 205 igmp->igmp_cksum = 0; 206 igmp->igmp_cksum = inet_cksum((u_short *)igmp, 207 IGMP_MINLEN + datalen); 208 209 if (IN_MULTICAST(ntohl(dst))) k_set_if(src); 210 if (dst == allhosts_group) k_set_loop(TRUE); 211 212 sdst.sin_addr.s_addr = dst; 213 if (sendto(igmp_socket, send_buf, ip->ip_len, 0, 214 (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { 215 if (errno == ENETDOWN) check_vif_state(); 216 else log(LOG_WARNING, errno, "sendto on %s", inet_fmt(src, s1)); 217 } 218 219 if (dst == allhosts_group) k_set_loop(FALSE); 220 221 log(LOG_DEBUG, 0, "SENT %s from %-15s to %s", 222 packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2)); 223 } 224