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