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