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