Annotation of embedaddon/pimdd/pim.c, revision 1.1.1.1.2.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: *
1.1.1.1.2.1! misho 37: * $Id: pim.c,v 1.1.1.1 2017/06/12 07:58:55 misho Exp $
1.1 misho 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->pim_cksum = 0;
261: /* TODO: XXX: if start using this code for PIM_REGISTERS, exclude the
262: * encapsulated packet from the checsum.
263: */
264: pim->pim_cksum = inet_cksum((u_int16 *)pim,
265: sizeof(pim_header_t) + datalen);
266:
267: if (IN_MULTICAST(ntohl(dst))) {
268: k_set_if(pim_socket, src);
269: if ((dst == allhosts_group) || (dst == allrouters_group) ||
270: (dst == allpimrouters_group)) {
271: setloop = 1;
272: k_set_loop(pim_socket, TRUE);
273: }
274: #ifdef RAW_OUTPUT_IS_RAW
275: ip->ip_ttl = curttl;
276: } else {
277: ip->ip_ttl = MAXTTL;
278: #endif /* RAW_OUTPUT_IS_RAW */
279: }
280:
281: bzero((void *)&sdst, sizeof(sdst));
282: sdst.sin_family = AF_INET;
283: #ifdef HAVE_SA_LEN
284: sdst.sin_len = sizeof(sdst);
285: #endif
286: sdst.sin_addr.s_addr = dst;
287: if (sendto(pim_socket, buf, sendlen, 0,
288: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
289: if (errno == ENETDOWN)
290: check_vif_state();
291: else
292: log(LOG_WARNING, errno, "sendto from %s to %s",
293: inet_fmt(src, s1), inet_fmt(dst, s2));
294: if (setloop)
295: k_set_loop(pim_socket, FALSE);
296: return;
297: }
298:
299: if (setloop)
300: k_set_loop(pim_socket, FALSE);
301:
302: IF_DEBUG(DEBUG_PIM_DETAIL) {
303: IF_DEBUG(DEBUG_PIM) {
304: log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
305: packet_kind(IPPROTO_PIM, type, 0),
306: src == INADDR_ANY_N ? "INADDR_ANY" :
307: inet_fmt(src, s1), inet_fmt(dst, s2));
308: }
309: }
310: }
311:
312: u_int pim_send_cnt = 0;
313: #define SEND_DEBUG_NUMBER 50
314:
315:
316: /* TODO: This can be merged with the above procedure */
317: /*
318: * Send an unicast PIM packet from src to dst, PIM message type = "type"
319: * and data length (after the PIM common header) = "datalen"
320: */
321: void
322: send_pim_unicast(buf, src, dst, type, datalen)
323: char *buf;
324: u_int32 src, dst;
325: int type, datalen;
326: {
327: struct sockaddr_in sdst;
328: struct ip *ip;
329: pim_header_t *pim;
330: int sendlen;
331: #ifdef RAW_OUTPUT_IS_RAW
332: extern int curttl;
333: #endif /* RAW_OUTPUT_IS_RAW */
334:
335: /* Prepare the IP header */
336: ip = (struct ip *)buf;
337: ip->ip_len = sizeof(struct ip) + sizeof(pim_header_t) + datalen;
338: ip->ip_src.s_addr = src;
339: ip->ip_dst.s_addr = dst;
340: sendlen = ip->ip_len;
341: /* TODO: XXX: setup the TTL from the inner mcast packet? */
342: ip->ip_ttl = MAXTTL;
343: #ifdef RAW_OUTPUT_IS_RAW
344: ip->ip_len = htons(ip->ip_len);
345: #endif /* RAW_OUTPUT_IS_RAW */
346:
347: /* Prepare the PIM packet */
348: pim = (pim_header_t *)(buf + sizeof(struct ip));
349: pim->pim_vers = PIM_PROTOCOL_VERSION;
350: pim->pim_type = type;
351: pim->pim_cksum = 0;
352:
353: bzero((void *)&sdst, sizeof(sdst));
354: sdst.sin_family = AF_INET;
355: #ifdef HAVE_SA_LEN
356: sdst.sin_len = sizeof(sdst);
357: #endif
358: sdst.sin_addr.s_addr = dst;
359: if (sendto(pim_socket, buf, sendlen, 0,
360: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
361: if (errno == ENETDOWN)
362: check_vif_state();
363: else
364: log(LOG_WARNING, errno, "sendto from %s to %s",
365: inet_fmt(src, s1), inet_fmt(dst, s2));
366: }
367:
368: IF_DEBUG(DEBUG_PIM_DETAIL) {
369: IF_DEBUG(DEBUG_PIM) {
370: /* TODO: use pim_send_cnt ?
371: if (++pim_send_cnt > SEND_DEBUG_NUMBER) {
372: pim_send_cnt = 0;
373: log(LOG_DEBUG, 0, "sending %s from %-15s to %s",
374: packet_kind(IPPROTO_PIM, type, 0),
375: inet_fmt(src, s1), inet_fmt(dst, s2));
376: }
377: */
378: log(LOG_DEBUG, 0, "sending %s from %-15s to %s",
379: packet_kind(IPPROTO_PIM, type, 0),
380: inet_fmt(src, s1), inet_fmt(dst, s2));
381: }
382: }
383: }
384:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>