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