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