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