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.1 1994/01/11 20:15:53 brezak Exp $ 12 */ 13 14 #ifndef lint 15 static char rcsid[] = "$Id: igmp.c,v 1.1 1994/01/11 20:15:53 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_p = IPPROTO_IGMP; 51 ip->ip_ttl = MAXTTL; /* applies to unicasts only */ 52 53 allhosts_group = htonl(INADDR_ALLHOSTS_GROUP); 54 dvmrp_group = htonl(INADDR_DVMRP_GROUP); 55 } 56 57 static char *packet_kind(type, code) 58 u_char type, code; 59 { 60 switch (type) { 61 case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query "; 62 case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report "; 63 case IGMP_DVMRP: 64 switch (code) { 65 case DVMRP_PROBE: return "neighbor probe "; 66 case DVMRP_REPORT: return "route report "; 67 case DVMRP_ASK_NEIGHBORS: return "neighbor request "; 68 case DVMRP_NEIGHBORS: return "neighbor list "; 69 case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2"; 70 case DVMRP_NEIGHBORS2: return "neighbor list 2 "; 71 default: return "unknown DVMRP msg "; 72 } 73 default: return "unknown IGMP msg "; 74 } 75 } 76 77 /* 78 * Process a newly received IGMP packet that is sitting in the input 79 * packet buffer. 80 */ 81 void accept_igmp(recvlen) 82 int recvlen; 83 { 84 register vifi_t vifi; 85 register u_long src, dst, group; 86 struct ip *ip; 87 struct igmp *igmp; 88 int ipdatalen, iphdrlen, igmpdatalen; 89 90 if (recvlen < sizeof(struct ip)) { 91 log(LOG_WARNING, 0, 92 "received packet too short (%u bytes) for IP header", recvlen); 93 return; 94 } 95 96 ip = (struct ip *)recv_buf; 97 src = ip->ip_src.s_addr; 98 dst = ip->ip_dst.s_addr; 99 iphdrlen = ip->ip_hl << 2; 100 ipdatalen = ip->ip_len; 101 if (iphdrlen + ipdatalen != recvlen) { 102 log(LOG_WARNING, 0, 103 "received packet shorter (%u bytes) than hdr+data length (%u+%u)", 104 recvlen, iphdrlen, ipdatalen); 105 return; 106 } 107 108 igmp = (struct igmp *)(recv_buf + iphdrlen); 109 group = igmp->igmp_group.s_addr; 110 igmpdatalen = ipdatalen - IGMP_MINLEN; 111 if (igmpdatalen < 0) { 112 log(LOG_WARNING, 0, 113 "received IP data field too short (%u bytes) for IGMP, from %s", 114 ipdatalen, inet_fmt(src, s1)); 115 return; 116 } 117 118 log(LOG_DEBUG, 0, "RECV %s from %-15s to %s", 119 packet_kind(igmp->igmp_type, igmp->igmp_code), 120 inet_fmt(src, s1), inet_fmt(dst, s2)); 121 122 switch (igmp->igmp_type) { 123 124 case IGMP_HOST_MEMBERSHIP_QUERY: 125 return; /* Answered automatically by the kernel. */ 126 127 case IGMP_HOST_MEMBERSHIP_REPORT: 128 accept_group_report(src, dst, group); 129 return; 130 131 case IGMP_DVMRP: 132 switch (igmp->igmp_code) { 133 134 case DVMRP_PROBE: 135 accept_probe(src, dst); 136 return; 137 138 case DVMRP_REPORT: 139 accept_report(src, dst, 140 (char *)(igmp+1), igmpdatalen); 141 return; 142 143 case DVMRP_ASK_NEIGHBORS: 144 accept_neighbor_request(src, dst); 145 return; 146 147 case DVMRP_ASK_NEIGHBORS2: 148 accept_neighbor_request2(src, dst); 149 return; 150 151 case DVMRP_NEIGHBORS: 152 accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen, 153 group); 154 return; 155 156 case DVMRP_NEIGHBORS2: 157 accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen, 158 group); 159 return; 160 161 default: 162 log(LOG_INFO, 0, 163 "ignoring unknown DVMRP message code %u from %s to %s", 164 igmp->igmp_code, inet_fmt(src, s1), 165 inet_fmt(dst, s2)); 166 return; 167 } 168 169 default: 170 log(LOG_INFO, 0, 171 "ignoring unknown IGMP message type %u from %s to %s", 172 igmp->igmp_type, inet_fmt(src, s1), 173 inet_fmt(dst, s2)); 174 return; 175 } 176 } 177 178 179 /* 180 * Construct an IGMP message in the output packet buffer. The caller may 181 * have already placed data in that buffer, of length 'datalen'. Then send 182 * the message from the interface with IP address 'src' to destination 'dst'. 183 */ 184 void send_igmp(src, dst, type, code, group, datalen) 185 u_long src, dst; 186 int type, code; 187 u_long group; 188 int datalen; 189 { 190 static struct sockaddr_in sdst = {AF_INET}; 191 struct ip *ip; 192 struct igmp *igmp; 193 194 ip = (struct ip *)send_buf; 195 ip->ip_src.s_addr = src; 196 ip->ip_dst.s_addr = dst; 197 ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; 198 199 igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN); 200 igmp->igmp_type = type; 201 igmp->igmp_code = code; 202 igmp->igmp_group.s_addr = group; 203 igmp->igmp_cksum = 0; 204 igmp->igmp_cksum = inet_cksum((u_short *)igmp, 205 IGMP_MINLEN + datalen); 206 207 if (IN_MULTICAST(ntohl(dst))) k_set_if(src); 208 if (dst == allhosts_group) k_set_loop(TRUE); 209 210 sdst.sin_addr.s_addr = dst; 211 if (sendto(igmp_socket, send_buf, ip->ip_len, 0, 212 (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { 213 if (errno == ENETDOWN) check_vif_state(); 214 else log(LOG_WARNING, errno, "sendto on %s", inet_fmt(src, s1)); 215 } 216 217 if (dst == allhosts_group) k_set_loop(FALSE); 218 219 log(LOG_DEBUG, 0, "SENT %s from %-15s to %s", 220 packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2)); 221 } 222