Annotation of embedaddon/pimdd/pim.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1998 by the University of Southern California.
3: * All rights reserved.
4: *
5: * Permission to use, copy, modify, and distribute this software and
6: * its documentation in source and binary forms for lawful
7: * purposes and without fee is hereby granted, provided
8: * that the above copyright notice appear in all copies and that both
9: * the copyright notice and this permission notice appear in supporting
10: * documentation, and that any documentation, advertising materials,
11: * and other materials related to such distribution and use acknowledge
12: * that the software was developed by the University of Southern
13: * California and/or Information Sciences Institute.
14: * The name of the University of Southern California may not
15: * be used to endorse or promote products derived from this software
16: * without specific prior written permission.
17: *
18: * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19: * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
20: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
23: * NON-INFRINGEMENT.
24: *
25: * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27: * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28: * THE USE OR PERFORMANCE OF THIS SOFTWARE.
29: *
30: * Other copyrights might apply to parts of this software and are so
31: * noted when applicable.
32: */
33: /*
34: * Questions concerning this software should be directed to
35: * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
36: *
37: * $Id: pim.c,v 1.7 1998/12/22 21:50:17 kurtw Exp $
38: */
39:
40: #include "defs.h"
41:
42: /*
43: * Exported variables.
44: */
45: char *pim_recv_buf; /* input packet buffer */
46: char *pim_send_buf; /* output packet buffer */
47:
48: u_int32 allpimrouters_group; /* ALL_PIM_ROUTERS group (net order) */
49: int pim_socket; /* socket for PIM control msgs */
50:
51: /*
52: * Local function definitions.
53: */
54: static void pim_read __P((int f, fd_set *rfd));
55: static void accept_pim __P((int recvlen));
56:
57:
58: void
59: init_pim()
60: {
61: struct ip *ip;
62:
63: if ((pim_socket = socket(AF_INET, SOCK_RAW, IPPROTO_PIM)) < 0)
64: log(LOG_ERR, errno, "PIM socket");
65:
66: k_hdr_include(pim_socket, TRUE); /* include IP header when sending */
67: k_set_rcvbuf(pim_socket, SO_RECV_BUF_SIZE_MAX,
68: SO_RECV_BUF_SIZE_MIN); /* lots of input buffering */
69: k_set_ttl(pim_socket, MINTTL); /* restrict multicasts to one hop */
70: k_set_loop(pim_socket, FALSE); /* disable multicast loopback */
71:
72: allpimrouters_group = htonl(INADDR_ALL_PIM_ROUTERS);
73:
74: pim_recv_buf = malloc(RECV_BUF_SIZE);
75: pim_send_buf = malloc(RECV_BUF_SIZE);
76:
77: /* One time setup in the buffers */
78: ip = (struct ip *)pim_send_buf;
79: ip->ip_v = IPVERSION;
80: ip->ip_hl = (sizeof(struct ip) >> 2);
81: ip->ip_tos = 0; /* TODO: setup?? */
82: ip->ip_id = 0; /* let kernel fill in */
83: ip->ip_off = 0;
84: ip->ip_p = IPPROTO_PIM;
85: ip->ip_sum = 0; /* let kernel fill in */
86:
87: if (register_input_handler(pim_socket, pim_read) < 0)
88: log(LOG_ERR, 0, "cannot register pim_read() as an input handler");
89:
90: VIFM_CLRALL(nbr_vifs);
91: }
92:
93:
94: /* Read a PIM message */
95: static void
96: pim_read(f, rfd)
97: int f;
98: fd_set *rfd;
99: {
100: register int pim_recvlen;
101: int dummy = 0;
102: #ifdef SYSV
103: sigset_t block, oblock;
104: #else
105: register int omask;
106: #endif
107:
108: pim_recvlen = recvfrom(pim_socket, pim_recv_buf, RECV_BUF_SIZE,
109: 0, NULL, &dummy);
110:
111: if (pim_recvlen < 0) {
112: if (errno != EINTR)
113: log(LOG_ERR, errno, "PIM recvfrom");
114: return;
115: }
116:
117: #ifdef SYSV
118: (void)sigemptyset(&block);
119: (void)sigaddset(&block, SIGALRM);
120: if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
121: log(LOG_ERR, errno, "sigprocmask");
122: #else
123: /* Use of omask taken from main() */
124: omask = sigblock(sigmask(SIGALRM));
125: #endif /* SYSV */
126:
127: accept_pim(pim_recvlen);
128:
129: #ifdef SYSV
130: (void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
131: #else
132: (void)sigsetmask(omask);
133: #endif /* SYSV */
134: }
135:
136:
137: static void
138: accept_pim(recvlen)
139: int recvlen;
140: {
141: u_int32 src, dst;
142: register struct ip *ip;
143: register pim_header_t *pim;
144: int iphdrlen, pimlen;
145:
146: if (recvlen < sizeof(struct ip)) {
147: log(LOG_WARNING, 0, "packet too short (%u bytes) for IP header",
148: recvlen);
149: return;
150: }
151:
152: ip = (struct ip *)pim_recv_buf;
153: src = ip->ip_src.s_addr;
154: dst = ip->ip_dst.s_addr;
155: iphdrlen = ip->ip_hl << 2;
156:
157: pim = (pim_header_t *)(pim_recv_buf + iphdrlen);
158: pimlen = recvlen - iphdrlen;
159: if (pimlen < sizeof(pim)) {
160: log(LOG_WARNING, 0,
161: "IP data field too short (%u bytes) for PIM header, from %s to %s",
162: pimlen, inet_fmt(src, s1), inet_fmt(dst, s2));
163: return;
164: }
165:
166: #ifdef NOSUCHDEF /* TODO: delete. Too noisy */
167: IF_DEBUG(DEBUG_PIM_DETAIL) {
168: IF_DEBUG(DEBUG_PIM) {
169: log(LOG_DEBUG, 0, "Receiving %s from %-15s to %s ",
170: packet_kind(IPPROTO_PIM, pim->pim_type, 0),
171: inet_fmt(src, s1), inet_fmt(dst, s2));
172: log(LOG_DEBUG, 0, "PIM type is %u", pim->pim_type);
173: }
174: }
175: #endif /* NOSUCHDEF */
176:
177:
178: /* TODO: Check PIM version */
179: /* TODO: check the dest. is ALL_PIM_ROUTERS (if multicast address) */
180: /* TODO: Checksum verification is done in each of the processing functions.
181: * No need for chechsum, if already done in the kernel?
182: */
183: switch (pim->pim_type) {
184: case PIM_HELLO:
185: receive_pim_hello(src, dst, (char *)(pim), pimlen);
186: break;
187: case PIM_REGISTER:
188: log(LOG_INFO, 0, "ignore %s from %s to %s",
189: packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1),
190: inet_fmt(dst, s2));
191: break;
192: case PIM_REGISTER_STOP:
193: log(LOG_INFO, 0, "ignore %s from %s to %s",
194: packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1),
195: inet_fmt(dst, s2));
196: break;
197: case PIM_JOIN_PRUNE:
198: receive_pim_join_prune(src, dst, (char *)(pim), pimlen);
199: break;
200: case PIM_BOOTSTRAP:
201: log(LOG_INFO, 0, "ignore %s from %s to %s",
202: packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1),
203: inet_fmt(dst, s2));
204: break;
205: case PIM_ASSERT:
206: receive_pim_assert(src, dst, (char *)(pim), pimlen);
207: break;
208: case PIM_GRAFT:
209: case PIM_GRAFT_ACK:
210: receive_pim_graft(src, dst, (char *)(pim), pimlen, pim->pim_type);
211: break;
212: case PIM_CAND_RP_ADV:
213: log(LOG_INFO, 0, "ignore %s from %s to %s",
214: packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1),
215: inet_fmt(dst, s2));
216: break;
217: default:
218: log(LOG_INFO, 0,
219: "ignore unknown PIM message code %u from %s to %s",
220: pim->pim_type, inet_fmt(src, s1), inet_fmt(dst, s2));
221: break;
222: }
223: }
224:
225:
226: /*
227: * Send a multicast PIM packet from src to dst, PIM message type = "type"
228: * and data length (after the PIM header) = "datalen"
229: */
230: void
231: send_pim(buf, src, dst, type, datalen)
232: char *buf;
233: u_int32 src, dst;
234: int type, datalen;
235: {
236: struct sockaddr_in sdst;
237: struct ip *ip;
238: pim_header_t *pim;
239: int sendlen;
240: #ifdef RAW_OUTPUT_IS_RAW
241: extern int curttl;
242: #endif /* RAW_OUTPUT_IS_RAW */
243: int setloop = 0;
244:
245: /* Prepare the IP header */
246: ip = (struct ip *)buf;
247: ip->ip_len = sizeof(struct ip) + sizeof(pim_header_t) + datalen;
248: ip->ip_src.s_addr = src;
249: ip->ip_dst.s_addr = dst;
250: ip->ip_ttl = MAXTTL; /* applies to unicast only */
251: sendlen = ip->ip_len;
252: #ifdef RAW_OUTPUT_IS_RAW
253: ip->ip_len = htons(ip->ip_len);
254: #endif /* RAW_OUTPUT_IS_RAW */
255:
256: /* Prepare the PIM packet */
257: pim = (pim_header_t *)(buf + sizeof(struct ip));
258: pim->pim_type = type;
259: pim->pim_vers = PIM_PROTOCOL_VERSION;
260: pim->reserved = 0;
261: pim->pim_cksum = 0;
262: /* TODO: XXX: if start using this code for PIM_REGISTERS, exclude the
263: * encapsulated packet from the checsum.
264: */
265: pim->pim_cksum = inet_cksum((u_int16 *)pim,
266: sizeof(pim_header_t) + datalen);
267:
268: if (IN_MULTICAST(ntohl(dst))) {
269: k_set_if(pim_socket, src);
270: if ((dst == allhosts_group) || (dst == allrouters_group) ||
271: (dst == allpimrouters_group)) {
272: setloop = 1;
273: k_set_loop(pim_socket, TRUE);
274: }
275: #ifdef RAW_OUTPUT_IS_RAW
276: ip->ip_ttl = curttl;
277: } else {
278: ip->ip_ttl = MAXTTL;
279: #endif /* RAW_OUTPUT_IS_RAW */
280: }
281:
282: bzero((void *)&sdst, sizeof(sdst));
283: sdst.sin_family = AF_INET;
284: #ifdef HAVE_SA_LEN
285: sdst.sin_len = sizeof(sdst);
286: #endif
287: sdst.sin_addr.s_addr = dst;
288: if (sendto(pim_socket, buf, sendlen, 0,
289: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
290: if (errno == ENETDOWN)
291: check_vif_state();
292: else
293: log(LOG_WARNING, errno, "sendto from %s to %s",
294: inet_fmt(src, s1), inet_fmt(dst, s2));
295: if (setloop)
296: k_set_loop(pim_socket, FALSE);
297: return;
298: }
299:
300: if (setloop)
301: k_set_loop(pim_socket, FALSE);
302:
303: IF_DEBUG(DEBUG_PIM_DETAIL) {
304: IF_DEBUG(DEBUG_PIM) {
305: log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
306: packet_kind(IPPROTO_PIM, type, 0),
307: src == INADDR_ANY_N ? "INADDR_ANY" :
308: inet_fmt(src, s1), inet_fmt(dst, s2));
309: }
310: }
311: }
312:
313: u_int pim_send_cnt = 0;
314: #define SEND_DEBUG_NUMBER 50
315:
316:
317: /* TODO: This can be merged with the above procedure */
318: /*
319: * Send an unicast PIM packet from src to dst, PIM message type = "type"
320: * and data length (after the PIM common header) = "datalen"
321: */
322: void
323: send_pim_unicast(buf, src, dst, type, datalen)
324: char *buf;
325: u_int32 src, dst;
326: int type, datalen;
327: {
328: struct sockaddr_in sdst;
329: struct ip *ip;
330: pim_header_t *pim;
331: int sendlen;
332: #ifdef RAW_OUTPUT_IS_RAW
333: extern int curttl;
334: #endif /* RAW_OUTPUT_IS_RAW */
335:
336: /* Prepare the IP header */
337: ip = (struct ip *)buf;
338: ip->ip_len = sizeof(struct ip) + sizeof(pim_header_t) + datalen;
339: ip->ip_src.s_addr = src;
340: ip->ip_dst.s_addr = dst;
341: sendlen = ip->ip_len;
342: /* TODO: XXX: setup the TTL from the inner mcast packet? */
343: ip->ip_ttl = MAXTTL;
344: #ifdef RAW_OUTPUT_IS_RAW
345: ip->ip_len = htons(ip->ip_len);
346: #endif /* RAW_OUTPUT_IS_RAW */
347:
348: /* Prepare the PIM packet */
349: pim = (pim_header_t *)(buf + sizeof(struct ip));
350: pim->pim_vers = PIM_PROTOCOL_VERSION;
351: pim->pim_type = type;
352: pim->reserved = 0;
353: pim->pim_cksum = 0;
354:
355: bzero((void *)&sdst, sizeof(sdst));
356: sdst.sin_family = AF_INET;
357: #ifdef HAVE_SA_LEN
358: sdst.sin_len = sizeof(sdst);
359: #endif
360: sdst.sin_addr.s_addr = dst;
361: if (sendto(pim_socket, buf, sendlen, 0,
362: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
363: if (errno == ENETDOWN)
364: check_vif_state();
365: else
366: log(LOG_WARNING, errno, "sendto from %s to %s",
367: inet_fmt(src, s1), inet_fmt(dst, s2));
368: }
369:
370: IF_DEBUG(DEBUG_PIM_DETAIL) {
371: IF_DEBUG(DEBUG_PIM) {
372: /* TODO: use pim_send_cnt ?
373: if (++pim_send_cnt > SEND_DEBUG_NUMBER) {
374: pim_send_cnt = 0;
375: log(LOG_DEBUG, 0, "sending %s from %-15s to %s",
376: packet_kind(IPPROTO_PIM, type, 0),
377: inet_fmt(src, s1), inet_fmt(dst, s2));
378: }
379: */
380: log(LOG_DEBUG, 0, "sending %s from %-15s to %s",
381: packet_kind(IPPROTO_PIM, type, 0),
382: inet_fmt(src, s1), inet_fmt(dst, s2));
383: }
384: }
385: }
386:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>