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