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