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