1: /*
2: * Copyright (c) 1993, 1998-2001.
3: * The University of Southern California/Information Sciences Institute.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: * 3. Neither the name of the project nor the names of its contributors
15: * may be used to endorse or promote products derived from this software
16: * without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28: * SUCH DAMAGE.
29: */
30:
31: /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
32: * April 1995.
33: */
34:
35: /* May 1995 -- Added support for Route Change Notification */
36:
37: #ifdef RSRR
38:
39: #include "defs.h"
40: #include <sys/param.h>
41: #ifdef HAVE_SA_LEN
42: #include <stddef.h> /* for offsetof */
43: #endif
44:
45: /*
46: * Local RSRR variables.
47: */
48: static int rsrr_socket; /* interface to reservation protocol */
49: static char *rsrr_recv_buf; /* RSRR receive buffer */
50: static char *rsrr_send_buf; /* RSRR send buffer */
51:
52: static struct sockaddr_un client_addr;
53: static socklen_t client_length = sizeof(client_addr);
54:
55: /*
56: * Procedure definitions needed internally.
57: */
58: static void rsrr_accept(size_t recvlen);
59: static void rsrr_accept_iq(void);
60: static int rsrr_accept_rq(struct rsrr_rq *route_query, u_char flags, struct gtable *gt_notify);
61: static void rsrr_read(int, fd_set *);
62: static int rsrr_send(int sendlen);
63: static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query);
64:
65: /* Initialize RSRR socket */
66: void rsrr_init(void)
67: {
68: int servlen;
69: struct sockaddr_un serv_addr;
70:
71: rsrr_recv_buf = (char *)malloc(RSRR_MAX_LEN);
72: rsrr_send_buf = (char *)malloc(RSRR_MAX_LEN);
73: if (!rsrr_recv_buf || !rsrr_send_buf)
74: logit(LOG_ERR, 0, "Ran out of memory in rsrr_init()");
75:
76: if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
77: logit(LOG_ERR, errno, "Cannot create RSRR socket");
78:
79: unlink(RSRR_SERV_PATH);
80: memset(&serv_addr, 0, sizeof(serv_addr));
81: serv_addr.sun_family = AF_UNIX;
82: strlcpy(serv_addr.sun_path, RSRR_SERV_PATH, sizeof(serv_addr.sun_path));
83: #ifdef HAVE_SA_LEN
84: servlen = offsetof(struct sockaddr_un, sun_path) + strlen(serv_addr.sun_path);
85: serv_addr.sun_len = servlen;
86: #else
87: servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
88: #endif
89:
90: if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
91: logit(LOG_ERR, errno, "Cannot bind RSRR socket");
92:
93: if (register_input_handler(rsrr_socket, rsrr_read) < 0)
94: logit(LOG_ERR, 0, "Could not register RSRR as an input handler");
95: }
96:
97: /* Read a message from the RSRR socket */
98: static void rsrr_read(int fd, fd_set UNUSED *rfd)
99: {
100: ssize_t rsrr_recvlen;
101:
102: memset(&client_addr, 0, sizeof(client_addr));
103: rsrr_recvlen = recvfrom(fd, rsrr_recv_buf, sizeof(rsrr_recv_buf),
104: 0, (struct sockaddr *)&client_addr, &client_length);
105: if (rsrr_recvlen < 0) {
106: if (errno != EINTR)
107: logit(LOG_ERR, errno, "RSRR recvfrom");
108: return;
109: }
110: rsrr_accept(rsrr_recvlen);
111: }
112:
113: /* Accept a message from the reservation protocol and take
114: * appropriate action.
115: */
116: static void rsrr_accept(size_t recvlen)
117: {
118: struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_recv_buf;
119: struct rsrr_rq *route_query;
120:
121: if (recvlen < RSRR_HEADER_LEN) {
122: logit(LOG_WARNING, 0, "Received RSRR packet of %d bytes, which is less than MIN size %d.",
123: recvlen, RSRR_HEADER_LEN);
124: return;
125: }
126:
127: if (rsrr->version > RSRR_MAX_VERSION || rsrr->version != 1) {
128: logit(LOG_WARNING, 0, "Received RSRR packet version %d, which I don't understand",
129: rsrr->version);
130: return;
131: }
132:
133: switch (rsrr->type) {
134: case RSRR_INITIAL_QUERY:
135: /* Send Initial Reply to client */
136: IF_DEBUG(DEBUG_RSRR) {
137: logit(LOG_DEBUG, 0, "Received Initial Query\n");
138: }
139: rsrr_accept_iq();
140: break;
141:
142: case RSRR_ROUTE_QUERY:
143: /* Check size */
144: if (recvlen < RSRR_RQ_LEN) {
145: logit(LOG_WARNING, 0, "Received Route Query of %d bytes, which is too small", recvlen);
146: break;
147: }
148: /* Get the query */
149: route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
150: IF_DEBUG(DEBUG_RSRR) {
151: logit(LOG_DEBUG, 0,
152: "Received Route Query for src %s grp %s notification %d",
153: inet_fmt(route_query->source_addr.s_addr, s1, sizeof(s1)),
154: inet_fmt(route_query->dest_addr.s_addr, s2, sizeof(s2)),
155: BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
156: }
157: /* Send Route Reply to client */
158: rsrr_accept_rq(route_query, rsrr->flags, NULL);
159: break;
160:
161: default:
162: logit(LOG_WARNING, 0, "Received RSRR packet type %d, which I don't handle", rsrr->type);
163: break;
164: }
165: }
166:
167: /* Send an Initial Reply to the reservation protocol. */
168: static void rsrr_accept_iq(void)
169: {
170: struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
171: struct rsrr_vif *vif_list;
172: struct uvif *v;
173: int vifi, sendlen;
174:
175: /* Check for space. There should be room for plenty of vifs,
176: * but we should check anyway.
177: */
178: if (numvifs > RSRR_MAX_VIFS) {
179: logit(LOG_WARNING, 0,
180: "Cannot send RSRR Route Reply because %d is too many vifs %d",
181: numvifs);
182: return;
183: }
184:
185: /* Set up message */
186: rsrr->version = 1;
187: rsrr->type = RSRR_INITIAL_REPLY;
188: rsrr->flags = 0;
189: rsrr->num = numvifs;
190:
191: vif_list = (struct rsrr_vif *)(rsrr_send_buf + RSRR_HEADER_LEN);
192:
193: /* Include the vif list. */
194: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
195: vif_list[vifi].id = vifi;
196: vif_list[vifi].status = 0;
197: if (v->uv_flags & VIFF_DISABLED)
198: BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
199: vif_list[vifi].threshold = v->uv_threshold;
200: vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
201: }
202:
203: /* Get the size. */
204: sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
205:
206: /* Send it. */
207: IF_DEBUG(DEBUG_RSRR) {
208: logit(LOG_DEBUG, 0, "Send RSRR Initial Reply");
209: }
210: rsrr_send(sendlen);
211: }
212:
213: /* Send a Route Reply to the reservation protocol. The Route Query
214: * contains the query to which we are responding. The flags contain
215: * the incoming flags from the query or, for route change
216: * notification, the flags that should be set for the reply. The
217: * kernel table entry contains the routing info to use for a route
218: * change notification.
219: */
220: /* XXX: must modify if your routing table structure/search is different */
221: static int rsrr_accept_rq(struct rsrr_rq *route_query, u_char flags, struct gtable *gt_notify)
222: {
223: struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
224: struct rsrr_rr *route_reply;
225: struct gtable *gt,local_g;
226: struct rtentry *r;
227: int sendlen;
228: u_long mcastgrp;
229:
230: /* Set up message */
231: rsrr->version = 1;
232: rsrr->type = RSRR_ROUTE_REPLY;
233: rsrr->flags = 0;
234: rsrr->num = 0;
235:
236: route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
237: route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
238: route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
239: route_reply->query_id = route_query->query_id;
240:
241: /* Blank routing entry for error. */
242: route_reply->in_vif = 0;
243: route_reply->reserved = 0;
244: route_reply->out_vif_bm = 0;
245:
246: /* Get the size. */
247: sendlen = RSRR_RR_LEN;
248:
249: /* If kernel table entry is defined, then we are sending a Route Reply
250: * due to a Route Change Notification event. Use the kernel table entry
251: * to supply the routing info.
252: */
253: if (gt_notify) {
254: /* Set flags */
255: rsrr->flags = flags;
256: /* Include the routing entry. */
257: route_reply->in_vif = gt_notify->gt_route->rt_parent;
258: if (BIT_TST(flags,RSRR_NOTIFICATION_BIT))
259: route_reply->out_vif_bm = gt_notify->gt_grpmems;
260: else
261: route_reply->out_vif_bm = 0;
262: } else if (find_src_grp(route_query->source_addr.s_addr, 0,
263: route_query->dest_addr.s_addr)) {
264:
265: /* Found kernel entry. Code taken from add_table_entry() */
266: gt = gtp ? gtp->gt_gnext : kernel_table;
267:
268: /* Include the routing entry. */
269: route_reply->in_vif = gt->gt_route->rt_parent;
270: route_reply->out_vif_bm = gt->gt_grpmems;
271:
272: /* Cache reply if using route change notification. */
273: if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
274: /* TODO: XXX: Originally the rsrr_cache() call was first, but
275: * I think this is incorrect, because rsrr_cache() checks the
276: * rsrr_send_buf "flag" first.
277: */
278: BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
279: rsrr_cache(gt, route_query);
280: }
281: } else {
282: /* No kernel entry; use routing table. */
283: r = determine_route(route_query->source_addr.s_addr);
284:
285: if (r != NULL) {
286: /* We need to mimic what will happen if a data packet
287: * is forwarded by multicast routing -- the kernel will
288: * make an upcall and mrouted will install a route in the kernel.
289: * Our outgoing vif bitmap should reflect what that table
290: * will look like. Grab code from add_table_entry().
291: * This is gross, but it's probably better to be accurate.
292: */
293:
294: gt = &local_g;
295: mcastgrp = route_query->dest_addr.s_addr;
296:
297: gt->gt_mcastgrp = mcastgrp;
298: gt->gt_grpmems = 0;
299: gt->gt_scope = 0;
300: gt->gt_route = r;
301:
302: /* obtain the multicast group membership list */
303: determine_forwvifs(gt);
304:
305: /* Include the routing entry. */
306: route_reply->in_vif = gt->gt_route->rt_parent;
307: route_reply->out_vif_bm = gt->gt_grpmems;
308: } else {
309: /* Set error bit. */
310: BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
311: }
312: }
313:
314: IF_DEBUG(DEBUG_RSRR) {
315: logit(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n",
316: gt_notify ? "Route Change: " : "",
317: inet_fmt(route_reply->source_addr.s_addr, s1, sizeof(s1)),
318: inet_fmt(route_reply->dest_addr.s_addr, s2, sizeof(s2)),
319: route_reply->in_vif,route_reply->out_vif_bm);
320: }
321:
322: /* Send it. */
323: return rsrr_send(sendlen);
324: }
325:
326: /* Send an RSRR message. */
327: static int rsrr_send(int sendlen)
328: {
329: int error;
330:
331: /* Send it. */
332: error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
333: (struct sockaddr *)&client_addr, client_length);
334:
335: /* Check for errors. */
336: if (error < 0) {
337: logit(LOG_WARNING, errno, "Failed send on RSRR socket");
338: } else if (error != sendlen) {
339: logit(LOG_WARNING, 0,
340: "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
341: }
342: return error;
343: }
344:
345: /* TODO: need to sort the rsrr_cache entries for faster access */
346: /* Cache a message being sent to a client. Currently only used for
347: * caching Route Reply messages for route change notification.
348: */
349: static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query)
350: {
351: struct rsrr_cache *rc, **rcnp;
352: struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
353:
354: rcnp = >->gt_rsrr_cache;
355: while ((rc = *rcnp) != NULL) {
356: if ((rc->route_query.source_addr.s_addr ==
357: route_query->source_addr.s_addr) &&
358: (rc->route_query.dest_addr.s_addr ==
359: route_query->dest_addr.s_addr) &&
360: (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
361: /* Cache entry already exists.
362: * Check if route notification bit has been cleared.
363: */
364: if (!BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT)) {
365: /* Delete cache entry. */
366: *rcnp = rc->next;
367: free(rc);
368: } else {
369: /* Update */
370: /* TODO: XXX: No need to update iif, oifs, flags */
371: rc->route_query.query_id = route_query->query_id;
372: IF_DEBUG(DEBUG_RSRR) {
373: logit(LOG_DEBUG, 0,
374: "Update cached query id %ld from client %s\n",
375: rc->route_query.query_id, rc->client_addr.sun_path);
376: }
377: }
378: return;
379: }
380: rcnp = &rc->next;
381: }
382:
383: /* Cache entry doesn't already exist. Create one and insert at
384: * front of list.
385: */
386: rc = (struct rsrr_cache *)malloc(sizeof(struct rsrr_cache));
387: if (rc == NULL)
388: logit(LOG_ERR, 0, "Ran out of memory in rsrr_cache()");
389:
390: rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
391: rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
392: rc->route_query.query_id = route_query->query_id;
393: strlcpy(rc->client_addr.sun_path, client_addr.sun_path, sizeof(rc->client_addr.sun_path));
394: rc->client_length = client_length;
395: rc->next = gt->gt_rsrr_cache;
396: gt->gt_rsrr_cache = rc;
397: IF_DEBUG(DEBUG_RSRR) {
398: logit(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
399: rc->route_query.query_id, rc->client_addr.sun_path);
400: }
401: }
402:
403: /* Send all the messages in the cache for particular routing entry.
404: * Currently this is used to send all the cached Route Reply messages
405: * for route change notification.
406: */
407: void rsrr_cache_send(struct gtable *gt, int notify)
408: {
409: struct rsrr_cache *rc, **rcnp;
410: u_char flags = 0;
411:
412: if (notify) {
413: BIT_SET(flags, RSRR_NOTIFICATION_BIT);
414: }
415:
416: rcnp = >->gt_rsrr_cache;
417: while ((rc = *rcnp) != NULL) {
418: if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
419: IF_DEBUG(DEBUG_RSRR) {
420: logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
421: rc->route_query.query_id,rc->client_addr.sun_path);
422: }
423: /* Delete cache entry. */
424: *rcnp = rc->next;
425: free(rc);
426: } else {
427: rcnp = &rc->next;
428: }
429: }
430: }
431:
432: /* Clean the cache by deleting all entries. */
433: void rsrr_cache_clean(struct gtable *gt)
434: {
435: struct rsrr_cache *rc, *rc_next;
436:
437: IF_DEBUG(DEBUG_RSRR) {
438: logit(LOG_DEBUG, 0, "cleaning cache for group %s\n",
439: inet_fmt(gt->gt_mcastgrp, s1, sizeof(s1)));
440: }
441: rc = gt->gt_rsrr_cache;
442: while (rc) {
443: rc_next = rc->next;
444: free(rc);
445: rc = rc_next;
446: }
447: gt->gt_rsrr_cache = NULL;
448: }
449:
450: void rsrr_clean(void)
451: {
452: unlink(RSRR_SERV_PATH);
453: }
454:
455: #endif /* RSRR */
456:
457: /**
458: * Local Variables:
459: * version-control: t
460: * indent-tabs-mode: t
461: * c-file-style: "ellemtel"
462: * c-basic-offset: 4
463: * End:
464: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>