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