Remove __P macros from src/usr.bin and src/usr.sbin.
[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.3 2003/11/03 19:31:38 eirikn 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()
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(f, rfd)
103         int f;
104         fd_set *rfd;
105 {
106     register int rsrr_recvlen;
107     
108     bzero((char *) &client_addr, sizeof(client_addr));
109     rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
110                             0, (struct sockaddr *)&client_addr, &client_length);
111     if (rsrr_recvlen < 0) {     
112         if (errno != EINTR)
113             log(LOG_ERR, errno, "RSRR recvfrom");
114         return;
115     }
116     rsrr_accept(rsrr_recvlen);
117 }
118
119 /* Accept a message from the reservation protocol and take
120  * appropriate action.
121  */
122 static void
123 rsrr_accept(recvlen)
124     int recvlen;
125 {
126     struct rsrr_header *rsrr;
127     struct rsrr_rq *route_query;
128     
129     if (recvlen < RSRR_HEADER_LEN) {
130         log(LOG_WARNING, 0,
131             "Received RSRR packet of %d bytes, which is less than min size",
132             recvlen);
133         return;
134     }
135     
136     rsrr = (struct rsrr_header *) rsrr_recv_buf;
137     
138     if (rsrr->version > RSRR_MAX_VERSION) {
139         log(LOG_WARNING, 0,
140             "Received RSRR packet version %d, which I don't understand",
141             rsrr->version);
142         return;
143     }
144     
145     switch (rsrr->version) {
146       case 1:
147         switch (rsrr->type) {
148           case RSRR_INITIAL_QUERY:
149             /* Send Initial Reply to client */
150             IF_DEBUG(DEBUG_RSRR)
151             log(LOG_DEBUG, 0, "Received Initial Query\n");
152             rsrr_accept_iq();
153             break;
154           case RSRR_ROUTE_QUERY:
155             /* Check size */
156             if (recvlen < RSRR_RQ_LEN) {
157                 log(LOG_WARNING, 0,
158                     "Received Route Query of %d bytes, which is too small",
159                     recvlen);
160                 break;
161             }
162             /* Get the query */
163             route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
164             IF_DEBUG(DEBUG_RSRR)
165             log(LOG_DEBUG, 0,
166                 "Received Route Query for src %s grp %s notification %d",
167                 inet_fmt(route_query->source_addr.s_addr, s1),
168                 inet_fmt(route_query->dest_addr.s_addr,s2),
169                 BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
170             /* Send Route Reply to client */
171             rsrr_accept_rq(route_query,rsrr->flags,NULL);
172             break;
173           default:
174             log(LOG_WARNING, 0,
175                 "Received RSRR packet type %d, which I don't handle",
176                 rsrr->type);
177             break;
178         }
179         break;
180         
181       default:
182         log(LOG_WARNING, 0,
183             "Received RSRR packet version %d, which I don't understand",
184             rsrr->version);
185         break;
186     }
187 }
188
189 /* Send an Initial Reply to the reservation protocol. */
190 static void
191 rsrr_accept_iq()
192 {
193     struct rsrr_header *rsrr;
194     struct rsrr_vif *vif_list;
195     struct uvif *v;
196     int vifi, sendlen;
197     
198     /* Check for space.  There should be room for plenty of vifs,
199      * but we should check anyway.
200      */
201     if (numvifs > RSRR_MAX_VIFS) {
202         log(LOG_WARNING, 0,
203             "Can't send RSRR Route Reply because %d is too many vifs",
204             numvifs);
205         return;
206     }
207     
208     /* Set up message */
209     rsrr = (struct rsrr_header *) rsrr_send_buf;
210     rsrr->version = 1;
211     rsrr->type = RSRR_INITIAL_REPLY;
212     rsrr->flags = 0;
213     rsrr->num = numvifs;
214     
215     vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
216     
217     /* Include the vif list. */
218     for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
219         vif_list[vifi].id = vifi;
220         vif_list[vifi].status = 0;
221         if (v->uv_flags & VIFF_DISABLED)
222             BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
223         vif_list[vifi].threshold = v->uv_threshold;
224         vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
225     }
226     
227     /* Get the size. */
228     sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
229     
230     /* Send it. */
231     IF_DEBUG(DEBUG_RSRR)
232     log(LOG_DEBUG, 0, "Send RSRR Initial Reply");
233     rsrr_send(sendlen);
234 }
235
236 /* Send a Route Reply to the reservation protocol.  The Route Query
237  * contains the query to which we are responding.  The flags contain
238  * the incoming flags from the query or, for route change
239  * notification, the flags that should be set for the reply.  The
240  * kernel table entry contains the routing info to use for a route
241  * change notification.
242  */
243 static int
244 rsrr_accept_rq(route_query,flags,gt_notify)
245     struct rsrr_rq *route_query;
246     int flags;
247     struct gtable *gt_notify;
248 {
249     struct rsrr_header *rsrr;
250     struct rsrr_rr *route_reply;
251     struct gtable *gt,local_g;
252     struct rtentry *r;
253     int sendlen;
254     u_long mcastgrp;
255     
256     /* Set up message */
257     rsrr = (struct rsrr_header *) rsrr_send_buf;
258     rsrr->version = 1;
259     rsrr->type = RSRR_ROUTE_REPLY;
260     rsrr->flags = 0;
261     rsrr->num = 0;
262     
263     route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
264     route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
265     route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
266     route_reply->query_id = route_query->query_id;
267     
268     /* Blank routing entry for error. */
269     route_reply->in_vif = 0;
270     route_reply->reserved = 0;
271     route_reply->out_vif_bm = 0;
272     
273     /* Get the size. */
274     sendlen = RSRR_RR_LEN;
275
276     /* If kernel table entry is defined, then we are sending a Route Reply
277      * due to a Route Change Notification event.  Use the kernel table entry
278      * to supply the routing info.
279      */
280     if (gt_notify) {
281         /* Set flags */
282         rsrr->flags = flags;
283         /* Include the routing entry. */
284         route_reply->in_vif = gt_notify->gt_route->rt_parent;
285         if (BIT_TST(flags,RSRR_NOTIFICATION_BIT))
286             route_reply->out_vif_bm = gt_notify->gt_grpmems;
287         else
288             route_reply->out_vif_bm = 0;
289     } else if (find_src_grp(route_query->source_addr.s_addr, 0,
290                             route_query->dest_addr.s_addr)) {
291
292         /* Found kernel entry. Code taken from add_table_entry() */
293         gt = gtp ? gtp->gt_gnext : kernel_table;
294         
295         /* Include the routing entry. */
296         route_reply->in_vif = gt->gt_route->rt_parent;
297         route_reply->out_vif_bm = gt->gt_grpmems;
298
299         /* Cache reply if using route change notification. */
300         if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
301             rsrr_cache(gt,route_query);
302             BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
303         }
304         
305     } else {
306         /* No kernel entry; use routing table. */
307         r = determine_route(route_query->source_addr.s_addr);
308         
309         if (r != NULL) {
310             /* We need to mimic what will happen if a data packet
311              * is forwarded by multicast routing -- the kernel will
312              * make an upcall and mrouted will install a route in the kernel.
313              * Our outgoing vif bitmap should reflect what that table
314              * will look like.  Grab code from add_table_entry().
315              * This is gross, but it's probably better to be accurate.
316              */
317             
318             gt = &local_g;
319             mcastgrp = route_query->dest_addr.s_addr;
320             
321             gt->gt_mcastgrp     = mcastgrp;
322             gt->gt_grpmems      = 0;
323             gt->gt_scope        = 0;
324             gt->gt_route        = r;
325             
326             /* obtain the multicast group membership list */
327             determine_forwvifs(gt);
328             
329             /* Include the routing entry. */
330             route_reply->in_vif = gt->gt_route->rt_parent;
331             route_reply->out_vif_bm = gt->gt_grpmems;
332
333         } else {
334             /* Set error bit. */
335             BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
336         }
337     }
338     
339     IF_DEBUG(DEBUG_RSRR)
340     log(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n",
341         gt_notify ? "Route Change: " : "",
342         inet_fmt(route_reply->source_addr.s_addr,s1),
343         inet_fmt(route_reply->dest_addr.s_addr,s2),
344         route_reply->in_vif,route_reply->out_vif_bm);
345     
346     /* Send it. */
347     return rsrr_send(sendlen);
348 }
349
350 /* Send an RSRR message. */
351 static int
352 rsrr_send(sendlen)
353     int sendlen;
354 {
355     int error;
356     
357     /* Send it. */
358     error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
359                    (struct sockaddr *)&client_addr, client_length);
360     
361     /* Check for errors. */
362     if (error < 0) {
363         log(LOG_WARNING, errno, "Failed send on RSRR socket");
364     } else if (error != sendlen) {
365         log(LOG_WARNING, 0,
366             "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
367     }
368     return error;
369 }
370
371 /* Cache a message being sent to a client.  Currently only used for
372  * caching Route Reply messages for route change notification.
373  */
374 static void
375 rsrr_cache(gt,route_query)
376     struct gtable *gt;
377     struct rsrr_rq *route_query;
378 {
379     struct rsrr_cache *rc, **rcnp;
380     struct rsrr_header *rsrr;
381
382     rsrr = (struct rsrr_header *) rsrr_send_buf;
383
384     rcnp = &gt->gt_rsrr_cache;
385     while ((rc = *rcnp) != NULL) {
386         if ((rc->route_query.source_addr.s_addr == 
387              route_query->source_addr.s_addr) &&
388             (rc->route_query.dest_addr.s_addr == 
389              route_query->dest_addr.s_addr) &&
390             (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
391             /* Cache entry already exists.
392              * Check if route notification bit has been cleared.
393              */
394             if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
395                 /* Delete cache entry. */
396                 *rcnp = rc->next;
397                 free(rc);
398             } else {
399                 /* Update */
400                 rc->route_query.query_id = route_query->query_id;
401                 IF_DEBUG(DEBUG_RSRR)
402                 log(LOG_DEBUG, 0,
403                         "Update cached query id %ld from client %s\n",
404                         rc->route_query.query_id, rc->client_addr.sun_path);
405             }
406             return;
407         }
408         rcnp = &rc->next;
409     }
410
411     /* Cache entry doesn't already exist.  Create one and insert at
412      * front of list.
413      */
414     rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
415     if (rc == NULL)
416         log(LOG_ERR, 0, "ran out of memory");
417     rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
418     rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
419     rc->route_query.query_id = route_query->query_id;
420     strcpy(rc->client_addr.sun_path, client_addr.sun_path);
421     rc->client_length = client_length;
422     rc->next = gt->gt_rsrr_cache;
423     gt->gt_rsrr_cache = rc;
424     IF_DEBUG(DEBUG_RSRR)
425     log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
426            rc->route_query.query_id,rc->client_addr.sun_path);
427 }
428
429 /* Send all the messages in the cache.  Currently this is used to send
430  * all the cached Route Reply messages for route change notification.
431  */
432 void
433 rsrr_cache_send(gt,notify)
434     struct gtable *gt;
435     int notify;
436 {
437     struct rsrr_cache *rc, **rcnp;
438     int flags = 0;
439
440     if (notify)
441         BIT_SET(flags,RSRR_NOTIFICATION_BIT);
442
443     rcnp = &gt->gt_rsrr_cache;
444     while ((rc = *rcnp) != NULL) {
445         if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
446             IF_DEBUG(DEBUG_RSRR)
447             log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
448                    rc->route_query.query_id,rc->client_addr.sun_path);
449             /* Delete cache entry. */
450             *rcnp = rc->next;
451             free(rc);
452         } else {
453             rcnp = &rc->next;
454         }
455     }
456 }
457
458 /* Clean the cache by deleting all entries. */
459 void
460 rsrr_cache_clean(gt)
461     struct gtable *gt;
462 {
463     struct rsrr_cache *rc,*rc_next;
464
465     IF_DEBUG(DEBUG_RSRR)
466     log(LOG_DEBUG, 0, "cleaning cache for group %s\n",
467                         inet_fmt(gt->gt_mcastgrp, s1));
468     rc = gt->gt_rsrr_cache;
469     while (rc) {
470         rc_next = rc->next;
471         free(rc);
472         rc = rc_next;
473     }
474     gt->gt_rsrr_cache = NULL;
475 }
476
477 void
478 rsrr_clean()
479 {
480     unlink(RSRR_SERV_PATH);
481 }
482
483 #endif /* RSRR */