2 * Copyright (c) 1993 by the University of Southern California
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.
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.
23 * Other copyrights might apply to parts of this software and are so
24 * noted when applicable.
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 $
30 /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
34 /* May 1995 -- Added support for Route Change Notification */
39 #include <sys/param.h>
41 #include <stddef.h> /* for offsetof */
47 int rsrr_socket; /* interface to reservation protocol */
50 * Global RSRR variables.
52 char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */
53 char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */
55 struct sockaddr_un client_addr;
56 int client_length = sizeof(client_addr);
60 * Procedure definitions needed internally.
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);
71 /* Initialize RSRR socket */
76 struct sockaddr_un serv_addr;
78 if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
79 log(LOG_ERR, errno, "Can't create RSRR socket");
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);
86 servlen = offsetof(struct sockaddr_un, sun_path) +
87 strlen(serv_addr.sun_path);
88 serv_addr.sun_len = servlen;
90 servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
93 if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
94 log(LOG_ERR, errno, "Can't bind RSRR socket");
96 if (register_input_handler(rsrr_socket, rsrr_read) < 0)
97 log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
100 /* Read a message from the RSRR socket */
106 register int rsrr_recvlen;
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) {
113 log(LOG_ERR, errno, "RSRR recvfrom");
116 rsrr_accept(rsrr_recvlen);
119 /* Accept a message from the reservation protocol and take
120 * appropriate action.
126 struct rsrr_header *rsrr;
127 struct rsrr_rq *route_query;
129 if (recvlen < RSRR_HEADER_LEN) {
131 "Received RSRR packet of %d bytes, which is less than min size",
136 rsrr = (struct rsrr_header *) rsrr_recv_buf;
138 if (rsrr->version > RSRR_MAX_VERSION) {
140 "Received RSRR packet version %d, which I don't understand",
145 switch (rsrr->version) {
147 switch (rsrr->type) {
148 case RSRR_INITIAL_QUERY:
149 /* Send Initial Reply to client */
151 log(LOG_DEBUG, 0, "Received Initial Query\n");
154 case RSRR_ROUTE_QUERY:
156 if (recvlen < RSRR_RQ_LEN) {
158 "Received Route Query of %d bytes, which is too small",
163 route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
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);
175 "Received RSRR packet type %d, which I don't handle",
183 "Received RSRR packet version %d, which I don't understand",
189 /* Send an Initial Reply to the reservation protocol. */
193 struct rsrr_header *rsrr;
194 struct rsrr_vif *vif_list;
198 /* Check for space. There should be room for plenty of vifs,
199 * but we should check anyway.
201 if (numvifs > RSRR_MAX_VIFS) {
203 "Can't send RSRR Route Reply because %d is too many vifs",
209 rsrr = (struct rsrr_header *) rsrr_send_buf;
211 rsrr->type = RSRR_INITIAL_REPLY;
215 vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
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;
228 sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
232 log(LOG_DEBUG, 0, "Send RSRR Initial Reply");
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.
244 rsrr_accept_rq(route_query,flags,gt_notify)
245 struct rsrr_rq *route_query;
247 struct gtable *gt_notify;
249 struct rsrr_header *rsrr;
250 struct rsrr_rr *route_reply;
251 struct gtable *gt,local_g;
257 rsrr = (struct rsrr_header *) rsrr_send_buf;
259 rsrr->type = RSRR_ROUTE_REPLY;
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;
268 /* Blank routing entry for error. */
269 route_reply->in_vif = 0;
270 route_reply->reserved = 0;
271 route_reply->out_vif_bm = 0;
274 sendlen = RSRR_RR_LEN;
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.
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;
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)) {
292 /* Found kernel entry. Code taken from add_table_entry() */
293 gt = gtp ? gtp->gt_gnext : kernel_table;
295 /* Include the routing entry. */
296 route_reply->in_vif = gt->gt_route->rt_parent;
297 route_reply->out_vif_bm = gt->gt_grpmems;
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);
306 /* No kernel entry; use routing table. */
307 r = determine_route(route_query->source_addr.s_addr);
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.
319 mcastgrp = route_query->dest_addr.s_addr;
321 gt->gt_mcastgrp = mcastgrp;
326 /* obtain the multicast group membership list */
327 determine_forwvifs(gt);
329 /* Include the routing entry. */
330 route_reply->in_vif = gt->gt_route->rt_parent;
331 route_reply->out_vif_bm = gt->gt_grpmems;
335 BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
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);
347 return rsrr_send(sendlen);
350 /* Send an RSRR message. */
358 error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
359 (struct sockaddr *)&client_addr, client_length);
361 /* Check for errors. */
363 log(LOG_WARNING, errno, "Failed send on RSRR socket");
364 } else if (error != sendlen) {
366 "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
371 /* Cache a message being sent to a client. Currently only used for
372 * caching Route Reply messages for route change notification.
375 rsrr_cache(gt,route_query)
377 struct rsrr_rq *route_query;
379 struct rsrr_cache *rc, **rcnp;
380 struct rsrr_header *rsrr;
382 rsrr = (struct rsrr_header *) rsrr_send_buf;
384 rcnp = >->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.
394 if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
395 /* Delete cache entry. */
400 rc->route_query.query_id = route_query->query_id;
403 "Update cached query id %ld from client %s\n",
404 rc->route_query.query_id, rc->client_addr.sun_path);
411 /* Cache entry doesn't already exist. Create one and insert at
414 rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
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;
425 log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
426 rc->route_query.query_id,rc->client_addr.sun_path);
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.
433 rsrr_cache_send(gt,notify)
437 struct rsrr_cache *rc, **rcnp;
441 BIT_SET(flags,RSRR_NOTIFICATION_BIT);
443 rcnp = >->gt_rsrr_cache;
444 while ((rc = *rcnp) != NULL) {
445 if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
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. */
458 /* Clean the cache by deleting all entries. */
463 struct rsrr_cache *rc,*rc_next;
466 log(LOG_DEBUG, 0, "cleaning cache for group %s\n",
467 inet_fmt(gt->gt_mcastgrp, s1));
468 rc = gt->gt_rsrr_cache;
474 gt->gt_rsrr_cache = NULL;
480 unlink(RSRR_SERV_PATH);