/* * @(#) $Id: rsrr_rsrr.c,v 4.5 1998/08/18 17:31:22 lindell Exp $ */ /************************ rsrr_rsrr.c **************************** * * * RSRR: Routing Support for Resource Reservations * * * *****************************************************************/ /**************************************************************************** RSVPD -- ReSerVation Protocol Daemon USC Information Sciences Institute Marina del Rey, California RSRR written by: Daniel Zappala, April 1995 RSRR modified by: Jeff Kann, Oct 1997 Copyright (c) 1996 by the University of Southern California All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation in source and binary forms for any purpose and without fee is hereby granted, provided that both the above copyright notice and this permission notice appear in all copies. and that any documentation, advertising materials, and other materials related to such distribution and use acknowledge that the software was developed in part by the University of Southern California, Information Sciences Institute. The name of the University may not be used to endorse or promote products derived from this software without specific prior written permission. THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Other copyrights might apply to parts of this software and are so noted when applicable. ********************************************************************/ #include "rsvp_daemon.h" #include #include #define Clear_LL_Vector(n) memset(&if_vec[n].if_LLifv, 0, sizeof(LLDAL_calls_t)) extern int errno; #if defined(PF_ROUTE) && !defined(sgi_53) #include #include #include #include #include #endif /* PF_ROUTE */ extern int rsrr_route_reply(u_long, net_addr *, net_addr *, u_short, bitmap *, int, int, int); /* * External Declarations */ extern int unicast_init(); extern char *bm_expand(); extern PSB *Find_fPSB(Session *, SENDER_TEMPLATE *); extern int locate_LIH(unsigned int, net_addr *); extern int lnum; extern bitmap bmp_unicast; #ifndef HOST_ONLY /* * No RSRR code for HOST_ONLY */ int seq; int shift; /* value to shift the vif returned by mrouted to inum in the if_vec[] */ /* * RSRR definitions */ struct rsrr_vif vif_list[RSRR_MAX_VIFS_V2]; /* RSVP vif list */ int gated_to_rsvpd[RSRR_MAX_VIFS_V2]; /* table to convert interface from gated to the interface in rsvpd */ int rsrr_socket; /* interface to reservation protocol */ int rsrr_use_v1_ipv4 = -1; /* RSRR v1 being used for IPv4 */ int rsrr_use_v2_ipv4 = -1; /* RSRR v2 being used for IPv4 */ #ifdef USE_IPV6 int rsrr_socket_v6; /* interface to reservation protocol */ int rsrr_use_v1_ipv6 = 0; /* RSRR v1 never used for IPv6 */ int rsrr_use_v2_ipv6 = 1; /* RSRR v2 should be used for IPv6 */ #endif /* USE_IPV6 */ #if defined(PF_ROUTE) && !defined(sgi_53) extern int rskt; /* Routing socket */ #endif /* PF_ROUTE */ char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */ char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */ struct sockaddr_un serv_addr_v4; /* V4 Server address */ struct sockaddr_un cli_addr_v4; /* V4 Client address */ #ifdef USE_IPV6 struct sockaddr_un serv_addr_v6; /* V6 Server address */ struct sockaddr_un cli_addr_v6; /* V6 Client address */ #endif /* USE_IPV6 */ int clilen, servlen; /* Lengths */ /* * External debugging definitions. */ extern char *inet_fmt(); #ifdef USE_IPV6 extern char *ip6_sprintf(); extern u_long ds_tobmp(); extern unsigned int addr_toidx(); #endif extern char s1[]; extern char s2[]; extern char s3[]; extern char s4[]; /* * Internal RSRR global variables. */ struct rsrr_query_table *rsrr_qt[RSRR_QT_SIZE]; /* Query table */ char s[2*RSRR_MAX_VIFS_V2]; /* * Forward Declarations */ void rsrr_init(); int rsrr_read(); int rsrr_send_iq(); int rsrr_send_rq(); int rsrr_send(); int rsrr_send0(); int rsrr_accept_ux(); int rsrr_accept_rt(); int rsrr_accept_ir_ux(); int rsrr_accept_ir_rt(); int rsrr_accept_rr_ux(); int rsrr_accept_rr_rt(); void rsrr_qt_init(); u_long rsrr_qt_getid(); void rsrr_qt_cache(); struct rsrr_query_table *rsrr_qt_lookup(); void rsrr_qt_delete(); int resv_exist(); void SetNotifyBit(); rsrr_bmp * convert(rsrr_bmp *, rsrr_bmp *); #ifdef SOLARIS /* * Routing socket indicies */ #define RTAX_DST 0 #define RTAX_GATEWAY 1 #define RTAX_NETMASK 2 #define RTAX_GENMASK 3 #define RTAX_IFP 4 #define RTAX_IFA 5 #define RTAX_AUTHOR 6 #define RTAX_BRD 7 #define RTAX_MAX 8 #endif /* * Initialize RSRR socket */ void rsrr_init() { struct stat sb; const char *check_v4 = RSRR_SERV_PATH; #ifdef USE_IPV6 const char *check_v6 = RSRR_SRV6_PATH; #endif /* USE_IPV6 */ #ifdef __FreeBSD__ const char *mrd_v4 = "/var/run/mrouted.pid"; #ifdef USE_IPV6 const char *mrd_v6 = "/var/run/gated.pid"; #endif /* USE_IPV6 */ #else const char *mrd_v4 = "/etc/mrouted.pid"; #ifdef USE_IPV6 const char *mrd_v6 = "/var/run/gated.pid"; #endif /* USE_IPV6 */ #endif /* __FreeBSD__ */ /* * Routing sockets are initiated inside unicast_init() */ unicast_init(); /* * UNIX domain socket to talk to IPv4 mrouted */ if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { log(LOG_ERR, errno, "Can't create RSRR V4 socket", 0); exit(-1); } #ifdef USE_IPV6 /* * UNIX domain socket to talk to IPv6 gated */ if ((rsrr_socket_v6 = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { log(LOG_ERR, errno, "Can't create RSRR V6 socket", 0); exit(-1); } #endif /* USE_IPV6 */ /* * Server's address. */ memset((char *) &serv_addr_v4, 0, sizeof(serv_addr_v4)); serv_addr_v4.sun_family = AF_UNIX; strcpy(serv_addr_v4.sun_path, RSRR_SERV_PATH); #ifdef USE_IPV6 memset((char *) &serv_addr_v6, 0, sizeof(serv_addr_v6)); serv_addr_v6.sun_family = AF_UNIX; strcpy(serv_addr_v6.sun_path, RSRR_SRV6_PATH); #endif /* USE_IPV6 */ /* * Here we assume the path for v4 and v6 are of the same lengths */ #ifdef STANDARD_C_LIBRARY servlen = (offsetof(struct sockaddr_un, sun_path) + strlen(serv_addr_v4.sun_path)); #else servlen = sizeof(serv_addr_v4.sun_family)+strlen(serv_addr_v4.sun_path); #endif #ifdef SOCKADDR_LEN serv_addr_v4.sun_len = servlen; #ifdef USE_IPV6 serv_addr_v6.sun_len = servlen; #endif /* USE_IPV6 */ #endif /* * Client's address. */ memset((char *) &cli_addr_v4, 0, sizeof(cli_addr_v4)); cli_addr_v4.sun_family = AF_UNIX; strcpy(cli_addr_v4.sun_path, RSRR_CLI_PATH); #ifdef USE_IPV6 memset((char *) &cli_addr_v6, 0, sizeof(cli_addr_v6)); cli_addr_v6.sun_family = AF_UNIX; strcpy(cli_addr_v6.sun_path, RSRR_CL6_PATH); #endif /* USE_IPV6 */ #ifdef STANDARD_C_LIBRARY clilen = (offsetof(struct sockaddr_un, sun_path) + strlen(cli_addr_v4.sun_path)); #else clilen = sizeof(cli_addr_v4.sun_family) + strlen(cli_addr_v4.sun_path); #endif #ifdef SOCKADDR_LEN cli_addr_v4.sun_len = clilen; #ifdef USE_IPV6 cli_addr_v6.sun_len = clilen; #endif /* USE_IPV6 */ #endif /* * Remove on the off-chance that it was left around. */ unlink(cli_addr_v4.sun_path); #ifdef USE_IPV6 unlink(cli_addr_v6.sun_path); #endif /* USE_IPV6 */ /* * bind this socket to our address */ if (bind(rsrr_socket, (struct sockaddr *)&cli_addr_v4, clilen) < 0) { log(LOG_ERR, errno, "Can't bind RSRR V4 socket", 0); exit(-1); } #ifdef USE_IPV6 if (bind(rsrr_socket_v6, (struct sockaddr *)&cli_addr_v6, clilen) < 0) { log(LOG_ERR, errno, "Can't bind RSRR V6 socket", 0); exit(-1); } #endif /* USE_IPV6 */ /* * check if the mulitcast routing daemon is running or it * has support for rsrr */ if (stat(check_v4, &sb) == -1 && errno == ENOENT) { /* * error = No such file or directory * this means either IPv4 mrouted is not running or * it is running but it wasn't compiled with RSRR * support */ NoV4Mroute = 1; if (stat(mrd_v4, &sb) == -1) { /* * no pid info for mrouted pid, it's not running */ log(LOG_ERR,0,"IPv4 Multicast Daemon is not running\n"); } else { /* * it may be running without RSRR support or the * pid file was left around without being removed */ log(LOG_ERR,0,"IPv4 Multicast Daemon was killed or " "it does not support RSRR\n"); } } else NoV4Mroute = 0; #ifdef USE_IPV6 if (stat(check_v6, &sb) == -1 && errno == ENOENT) { /* * error = No such file or directory * this means either IPv6 gated is not running or * it is running but it wasn't compiled with RSRR * support */ NoV6Mroute = 1; if (stat(mrd_v6, &sb) == -1) { /* * no pid info for gated pid, it's not running */ log(LOG_ERR,0,"IPv6 Multicast Daemon is not running\n"); } else { /* * it may be running without RSRR support or the * pid file was left around without being removed */ log(LOG_ERR,0,"IPv6 Multicast Daemon was killed or " "it does not support RSRR\n"); } } else NoV6Mroute = 0; #endif /* USE_IPV6 */ /* * initialize the query table */ rsrr_qt_init(); } /* * Read a message from the RSRR socket, and call rsrr_accept_xx to * process it. Return an error if the message is not of the type * specified. */ int rsrr_read(sock_type, expected_type) u_char sock_type; u_char expected_type; { int skt = -1; switch(sock_type) { case RSRR_SOCK_V4UX: /* * it's from IPv4 Unix domain socket */ skt = rsrr_socket; return rsrr_accept_ux(sock_type, skt, expected_type); break; #if defined(PF_ROUTE) && !defined(sgi_53) case RSRR_SOCK_RT: /* * it's from Unix routing socket */ skt = rskt; return 0; break; #endif /* PF_ROUTE */ #ifdef USE_IPV6 case RSRR_SOCK_V6UX: /* * it's from IPv6 Unix domain socket */ skt = rsrr_socket_v6; return rsrr_accept_ux(sock_type, skt, expected_type); #endif /* USE_IPV6 */ default: log(LOG_ERR, errno, "Unknown socket to RSRR", 0); exit(-1); break; } } /* * Send initial RSRR Interface Query message */ int rsrr_send0(int sendlen) { int rv = 0; int error_v4 = 0; #ifdef USE_IPV6 int error_v6 = 0; #endif /* USE_IPV6 */ if (!NoV4Mroute) { /* * IPv4 mrouted is running, send it */ error_v4 = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0, (struct sockaddr *)&serv_addr_v4, servlen); } #ifdef USE_IPV6 if (!NoV6Mroute) { /* * IPv6 gated is running, send it */ error_v6 = sendto(rsrr_socket_v6, rsrr_send_buf, sendlen, 0, (struct sockaddr *)&serv_addr_v6, servlen); } #endif /* USE_IPV6 */ if (!NoV4Mroute) { if (error_v4 == ECONNREFUSED) { /* * IPv4 mrouted is running, but the connection was refused * reset NoV4Mroute to be true */ log(LOG_ERR,errno,"Connection refused on RSRR V4 socket",0); NoV4Mroute = 1; rv = -1; } else if (error_v4 < 0) { /* * other errors */ log(LOG_ERR,errno,"Sending initially on RSRR V4 socket",0); NoV4Mroute = 1; rv = -1; } } #ifdef USE_IPV6 if (!NoV6Mroute) { if (error_v6 == ECONNREFUSED) { /* * IPv6 gated is running, but the connection was refused * reset NoV6Mroute to be true */ log(LOG_ERR,errno,"Connection refused on RSRR V6 socket",0); NoV6Mroute = 1; rv = -1; } else if (error_v6 < 0) { /* * other errors */ log(LOG_ERR,errno,"Sending initially on RSRR V6 socket",0); NoV6Mroute = 1; rv = -1; } } #endif /* USE_IPV6 */ return rv; } /* * Send a RSRR message */ int rsrr_send(type, sendlen) u_char type; int sendlen; { int error; if (type == RSRR_SOCK_V4UX) { /* * send the message through IPv4 UNIX domain socket */ error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0, (struct sockaddr *)&serv_addr_v4, servlen); if (error < 0) { log(LOG_ERR, errno, "Sending on RSRR V4 socket", 0); return -1; } if (error != sendlen) { log(LOG_ERR,0,"Sent only %d out of %d bytes on RSRR V4 socket\n", error, sendlen); return -1; } } #ifdef USE_IPV6 else if (type == RSRR_SOCK_V6UX) { /* * send the message through IPv6 UNIX domain socket */ error = sendto(rsrr_socket_v6, rsrr_send_buf, sendlen, 0, (struct sockaddr *)&serv_addr_v6, servlen); if (error < 0) { log(LOG_ERR, errno, "Sending on RSRR V6 socket", 0); return -1; } if (error != sendlen) { log(LOG_ERR, 0, "Sent only %d out of %d bytes on RSRR V6 socket\n", error, sendlen); return -1; } } #endif /* USE_IPV6 */ return 0; } /* * Handling incoming packet from specific Unix domain socket * The packet should conform to RSRR message types (v1 or v2) */ int rsrr_accept_ux(sock_type,skt,expected_type) u_char sock_type; int skt; u_char expected_type; { register int rsrr_recvlen; int dummy = 0; struct rsrr_header *rsrr; /* * receive from socket */ rsrr_recvlen = recvfrom(skt, rsrr_recv_buf, sizeof(rsrr_recv_buf), 0, (struct sockaddr *) 0, &dummy); if (rsrr_recvlen < 0) { log(LOG_ERR, errno, "recvfrom", 0); return -1; } if (rsrr_recvlen < RSRR_HEADER_LEN) { /* * truncated packet */ log(LOG_ERR, 0, "Received RSRR packet of %d bytes, which is less than min size", rsrr_recvlen); return -1; } rsrr = (struct rsrr_header *) rsrr_recv_buf; /* * replied version beyond our max supported version * This shouldn't happen if application do as the draft specified */ if (rsrr->version > RSRR_MAX_VERSION) { log(LOG_ERR, 0, "Received RSRR packet version %d, which I don't understand", rsrr->version); return -1; } /* * Check if expected type is specified and force match if it is. */ if (expected_type != RSRR_ALL_TYPES && rsrr->type != expected_type) { log(LOG_ERR, 0, "Received RSRR packet of type %d, but I'm expecting type %d\n", rsrr->type, expected_type); return -1; } switch (rsrr->version) { case 1: /* * RSRR version 1 */ switch (rsrr->type) { case RSRR_INTERFACE_REPLY: /* * Interface Reply message type */ if (rsrr_recvlen < (RSRR_HEADER_LEN + rsrr->num * RSRRV1_VIF_LEN)) { log(LOG_ERR, 0, "Received Interface Reply of %d bytes, which is too small\n", rsrr_recvlen); break; } if (sock_type == RSRR_SOCK_V4UX) { /* * from IPv4 socket */ if (rsrr->version < RSRR_MAX_VERSION) { /* * we can handle this packet * since it's within the max * version we declared */ rsrr_use_v1_ipv4 = 1; rsrr_use_v2_ipv4 = 0; } else { /* * we can use our max supported * version */ rsrr_use_v1_ipv4 = 0; rsrr_use_v2_ipv4 = 1; } } #ifdef USE_IPV6 else if (sock_type == RSRR_SOCK_V6UX) { /* * Should be error */ if (rsrr->flags == 1) log(LOG_ERR,errno,"RSRR_IR: Error in gated",0); else log(LOG_ERR,errno,"RSRR_IR: Wrong version",0); exit(-1); } #endif /* USE_IPV6 */ /* * accept this interface reply */ return rsrr_accept_ir_ux(sock_type, rsrr); case RSRR_ROUTE_REPLY: /* * Route Reply message type */ if (rsrr_recvlen < RSRRV1_RR_LEN) { log(LOG_ERR, 0, "Received Route Reply of %d bytes, which is too small\n", rsrr_recvlen); break; } if (sock_type == RSRR_SOCK_V4UX) { /* * from IPv4 socket */ if (!rsrr_use_v1_ipv4) { log(LOG_ERR,0,"RSRR_RR Version mismatched. Expecting 2"); return -1; } } #ifdef USE_IPV6 else if (sock_type == RSRR_SOCK_V6UX) { /* * from IPv6 socket */ log(LOG_ERR,0,"RSRR v1 does not support IPv6"); return -1; } #endif /* USE_IPV6 */ /* * accept this route reply */ return rsrr_accept_rr_ux(sock_type, rsrr); default: log(LOG_ERR, 0, "Received RSRR packet type %d, which I don't handle", rsrr->type); break; } break; case 2: /* * RSRR version 2 */ switch (rsrr->type) { case RSRR_INTERFACE_REPLY: /* * Interface Reply message type */ if (rsrr_recvlen < (RSRR_HEADER_LEN + rsrr->num*RSRR_VIF_LEN)) { log(LOG_ERR, 0, "Received Interface Reply of %d bytes, which is too small\n", rsrr_recvlen); break; } if (rsrr->flags == 1) { log(LOG_ERR, 0, "Error occurred during interface query"); break; } if (sock_type == RSRR_SOCK_V4UX) { /* * from IPv4 socket */ if (rsrr->version < RSRR_MAX_VERSION) { rsrr_use_v1_ipv4 = 1; rsrr_use_v2_ipv4 = 0; } else { rsrr_use_v1_ipv4 = 0; rsrr_use_v2_ipv4 = 1; } } #ifdef USE_IPV6 else if (sock_type == RSRR_SOCK_V6UX) { /* * from IPv6 socket */ if (rsrr->version < RSRR_MAX_VERSION) { /* * Impossible. Should be error */ log(LOG_ERR,errno,"Wrong version",0); exit(-1); } else { rsrr_use_v2_ipv6 = 1; rsrr_use_v1_ipv6 = 0; } } #endif /* USE_IPV6 */ /* * accept this interface reply */ return rsrr_accept_ir_ux(sock_type, rsrr); case RSRR_ROUTE_REPLY: /* * Route Reply message type */ if (rsrr_recvlen < RSRR_RR_LEN) { log(LOG_ERR, 0, "Received Route Reply of %d bytes, which is too small\n", rsrr_recvlen); break; } if (sock_type == RSRR_SOCK_V4UX) { /* * from IPv4 socket */ if (!rsrr_use_v2_ipv4) { log(LOG_ERR,0,"RSRR_RR Version mismatched. Expecting 1"); return -1; } } #ifdef USE_IPV6 else if (sock_type == RSRR_SOCK_V6UX) { /* * from IPv6 socket */ if (!rsrr_use_v2_ipv6) { log(LOG_ERR,0,"someting is wrong"); return -1; } } #endif /* USE_IPV6 */ /* * accept this route reply */ return rsrr_accept_rr_ux(sock_type, rsrr); default: log(LOG_ERR, 0, "Received RSRR packet type %d, which I don't handle", rsrr->type); break; } break; default: log(LOG_ERR, 0, "Received RSRR packet version %d, which I don't understand", rsrr->version); break; } return 0; } /* * to accept message coming in from the routing socket * this is useful for asynchronous reply from the kernel, * but currently it's not used due to the fast response * from the kernel and the extra overhead of listening * to all the messages received from the routing socket * that are not related to rsvpd. */ int rsrr_accept_rt(sock_type, skt, expected_type) u_char sock_type; int skt; u_char expected_type; { #if defined(PF_ROUTE) && !defined(sgi_53) /* * the routing socket used by SGI is not supported */ struct sockaddr *sa; #ifdef SOLARIS caddr_t cp; struct sockaddr *rti_info[RTA_NUMBITS]; #else struct sockaddr *rti_info[RTAX_MAX]; #endif net_addr dst; net_addr naddr; struct rt_msghdr *mhp; char buf[RTM_BUFLEN]; struct sockaddr_dl *sdlp; char ifname[IFNAMSIZ]; struct sockaddr_in *iifa; int ifnum; int len; int rv; int i; unsigned int ifidx = 0; #ifdef USE_IPV6 struct sockaddr_in6 *iifa6; #endif /* USE_IPV6 */ memset(buf, 0, sizeof buf); mhp = (struct rt_msghdr *)buf; sa = (struct sockaddr *)(mhp + 1); /* * Read the reply */ len = read(skt, buf, sizeof(buf)); /* * not for this process */ if (mhp->rtm_pid != getpid()) return 0; /* * Here we assume no RTM_IFINFO */ if (len < 0 || mhp->rtm_errno) { if (IsDebug(DEBUG_ROUTE)) log(LOG_DEBUG, errno, "unicast route lookup failed"); return -1; } if (len == 0) { log(LOG_ERR, 0, "unicast route lookup is confused"); return -1; } /* * collect all the information from the message */ #ifdef SOLARIS cp = (caddr_t)sa; for (i = 0; i < RTA_NUMBITS; i++) { switch (mhp->rtm_addrs & (1 << i)) { case RTA_DST: case RTA_GATEWAY: case RTA_NETMASK: case RTA_GENMASK: case RTA_AUTHOR: case RTA_IFA: rti_info[i] = (struct sockaddr *)cp; cp += sizeof (struct sockaddr_in); break; case RTA_IFP: rti_info[i] = (struct sockaddr *)cp; cp += sizeof (struct sockaddr_dl); break; } } #else for (i = 0; i < RTAX_MAX; i++) { if (mhp->rtm_addrs & (1 << i)) { rti_info[i] = sa; NEXT_SA(sa); } else rti_info[i] = NULL; } #endif /* * process the info */ if ((sa = rti_info[RTAX_IFP]) != NULL) { /* * outgoing data-link address for this unicast route */ sdlp = (struct sockaddr_dl *)sa; if (sdlp->sdl_family != AF_LINK || sdlp->sdl_nlen == 0) { if (IsDebug(DEBUG_ROUTE)) log(LOG_DEBUG, 0, "unicast route through weird ifp"); return -1; } strncpy(ifname, sdlp->sdl_data, sdlp->sdl_nlen); if (sdlp->sdl_nlen < IFNAMSIZ) ifname[sdlp->sdl_nlen] = '\0'; /* * get the outgoing interface index from the * interface name */ ifidx = if_nametoindex(ifname); } if ((sa = rti_info[RTAX_DST]) != NULL) { /* * destination address for this unicast route */ if (sa->sa_family == AF_INET) { NET_SET_ADDR_IPv4(&dst, ((struct sockaddr_in *)sa)->sin_addr); } #ifdef USE_IPV6 else if (sa->sa_family == AF_INET6) { NET_SET_ADDR_IPv6(&dst, ((struct sockaddr_in6 *)sa)->sin6_addr); } #endif /* USE_IPV6 */ } else return -1; if ((sa = rti_info[RTAX_IFA]) != NULL) { /* * get the outgoing interface address */ if (sa->sa_family == AF_INET) { iifa = (struct sockaddr_in *)sa; NET_SET_ADDR_IPv4(&naddr, iifa->sin_addr); } #ifdef USE_IPV6 else if (sa->sa_family == AF_INET6) { iifa6 = (struct sockaddr_in6 *)sa; NET_SET_ADDR_IPv6(&naddr, iifa6->sin6_addr); } #endif /* USE_IPV6 */ else return -1; /* * use the index and address to get the outgoing LIH * used within rsvpd for further processing */ ifnum = locate_LIH(ifidx, &naddr); if (ifnum == -1) /* * failed to locate the correct LIH */ return -1; else { /* * set up the outgoing bitmap and process it */ bmp_set(&bmp_unicast, ifnum); rv = rsrr_route_reply(seq,(net_addr *)0,&dst,(u_short)0, &bmp_unicast,1,0,0); return rv; } } else return -1; #endif /* PF_ROUTE */ return -1; } /* * Send an Interface Query to multicast routing */ int rsrr_send_iq(int note) { struct rsrr_header *rsrr; int sendlen; int rv; /* * Set up Interface Query message */ rsrr = (struct rsrr_header *) rsrr_send_buf; /* * Hack version number here to enable automatic version negotiation */ rsrr->version = 1; /* compatibility hack */ rsrr->type = RSRR_INTERFACE_QUERY; rsrr->flags = note; /* notification bit */ rsrr->num = 2; /* maximum supported version */ /* * Get the size. */ sendlen = RSRR_HEADER_LEN; if (IsDebug(DEBUG_RSRR)) log(LOG_DEBUG, 0, "> Interface Query\n"); /* * Send it. */ rv = rsrr_send0(sendlen); return (rv); } /* * Accept an Interface Reply. The reply contains the vifs that routing * is using; initiatlize our own vif structure so RSVP can keep track * of them. */ int rsrr_accept_ir_ux(sock_type,rsrr_in) u_char sock_type; struct rsrr_header *rsrr_in; { int vf,i; int base; static int first = 1; base = vif_num; if (sock_type == RSRR_SOCK_V4UX) { /* * increase the total number of vif number used by RSRR * and set up the variable shift to be used later when * interpreting the bitmap from mrouted */ vif_num += rsrr_in->num; shift = if_num; if (NoV4Mroute) { /* * This is the interface reply from IPv4 mrouted */ NoV4Mroute = 0; } if (IsDebug(DEBUG_RSRR)) log(LOG_DEBUG, 0, "< IPv4 Mcast Daemon Interface Reply with %d vifs\n",rsrr_in->num); } #ifdef USE_IPV6 else if (sock_type == RSRR_SOCK_V6UX) { /* * we don't increase the vif number here because the * IPv6 mrouting daemon we use does not use any virtual * interfaces as IPv4 mrouted does, thus all the interfaces * used here are logical */ if (NoV6Mroute) { /* * the interface reply from IPv6 mrouting daemon */ NoV6Mroute = 0; } if (IsDebug(DEBUG_RSRR)) log(LOG_DEBUG, 0, "< IPv6 Mcast Daemon Interface Reply with %d vifs\n",rsrr_in->num); } #endif /* USE_IPV6 */ /* * Initialize permanent RSVP vif_list and gated_to_rsvpd * conversion table responsible for translating the interface * number used by gated to the one used by rsvpd. Gated has * different numbers and ordering of the interfaces, thus we * have to do one more step for conversion. */ if (first == 1) { /* * first time being called here, do the initialization, * so we don't do this again when rsrr_accept_ir_ux is * called for the second time. rsrr_accept_ir_ux would * be called twice if both IPv4 mrouted and IPv6 gated * are both running with RSRR support */ for (vf=0; vf< RSRR_MAX_VIFS_V2; vf++) { BIT_SET(vif_list[vf].status,RSRR_M_DISABLED_BIT); gated_to_rsvpd[vf] = -1; } first = 0; } if (sock_type == RSRR_SOCK_V4UX) { /* * IPv4 */ if (rsrr_use_v1_ipv4) { /* * RSRR v1 */ struct rsrrv1_vif *vifs; /* * skip over the RSRR header */ vifs = (struct rsrrv1_vif *)(rsrr_recv_buf+RSRR_HEADER_LEN); /* * loop through all the interfaces from the * interface reply */ for (vf = 0; vf < rsrr_in->num; vf++) { /* * loop through the if_vec[] table we kept */ for (i = 0; i < lnum; i++) { /* * Skip over API interface */ if (IsNumAPI(i)) continue; /* * Find a matching address from if_vec */ if (vifs[vf].local_addr.s_addr == NET_GET_ADDR_IPv4(&NET_GET_IF_PHY_ADDR(&GET_IF(i))).s_addr) { /* * Build vif_list used by RSRR with * BobB's suggestion of correct value * for prefix */ vif_list[base+vf].id = vifs[vf].id; vif_list[base+vf].threshold = vifs[vf].threshold; vif_list[base+vf].prefix = 24; vif_list[base+vf].status = (u_char)vifs[vf].status; vif_list[base+vf].family = AF_INET; vif_list[base+vf].length = sizeof(struct in_addr); vif_list[base+vf].addr_v4.s_addr = vifs[vf].local_addr.s_addr; if (IsDebug(DEBUG_RSRR)) log(LOG_DEBUG, 0, "Configured vif %d with %s\n", vifs[vf].id, inet_fmt(vifs[vf].local_addr.s_addr,s1)); /* * append to end of if_vec[] */ strncpy(if_vec[if_num].if_name, if_vec[i].if_name, IFNAMSIZ); /* if_vec[if_num].if_index = if_vec[i].if_index; */ if_vec[if_num].if_index = vifs[vf].id; if_vec[if_num].if_unicast = i; if_vec[if_num].if_udpttl = if_vec[i].if_udpttl; if_vec[if_num].prefix = 24; if_vec[if_num].if_flags |= IF_FLAG_IFF_MC; if (BIT_TST(vifs[vf].status,RSRR_M_DISABLED_BIT)) if_vec[if_num].if_flags &= ~IF_FLAG_IFF_UP; else if_vec[if_num].if_flags |= IF_FLAG_IFF_UP; NET_SET_IF_VIF(&(if_vec[if_num].if_addr), NET_GET_IF_PHY_ADDR(&GET_IF(i)), vifs[vf].id); Clear_LL_Vector(if_num); if_num++; break; } } } if (i == if_num) { log(LOG_ERR, 0,"VIF config error\n"); exit(-1); } } else { /* * Use RSRR v2 format */ struct rsrr_vif *vifs; /* * skip over the RSRR header */ vifs = (struct rsrr_vif *)(rsrr_recv_buf+RSRR_HEADER_LEN); /* * loop through all the interfaces from the * interface reply */ for (vf = 0; vf < rsrr_in->num; vf++) { /* * loop through the if_vec[] table we kept */ for (i = 0; i < lnum; i++) { /* * Skip over API interface */ if (IsNumAPI(i)) continue; if (vifs[vf].addr_v4.s_addr == NET_GET_ADDR_IPv4(&NET_GET_IF_PHY_ADDR(&GET_IF(i))).s_addr) { vif_list[base+vf].id = vifs[vf].id; vif_list[base+vf].threshold = vifs[vf].threshold; vif_list[base+vf].prefix = vifs[vf].prefix; vif_list[base+vf].status = vifs[vf].status; vif_list[base+vf].family = vifs[vf].family; vif_list[base+vf].length = vifs[vf].length; vif_list[base+vf].addr_v4 = vifs[vf].addr_v4; if (IsDebug(DEBUG_RSRR)) log(LOG_DEBUG, 0, "Configured vif %d with %s\n", vifs[vf].id, inet_fmt(vifs[vf].addr_v4.s_addr,s1)); /* * append to end of if_vec */ strncpy(if_vec[if_num].if_name, if_vec[i].if_name, IFNAMSIZ); /* if_vec[if_num].if_index = if_vec[i].if_index; */ if_vec[if_num].if_index = vifs[vf].id; if_vec[if_num].if_unicast = i; if_vec[if_num].if_udpttl = if_vec[i].if_udpttl; if_vec[if_num].prefix = vifs[vf].prefix; if_vec[if_num].if_flags |= IF_FLAG_IFF_MC; if (BIT_TST(vifs[vf].status,RSRR_M_DISABLED_BIT)) if_vec[if_num].if_flags &= ~IF_FLAG_IFF_UP; else if_vec[if_num].if_flags |= IF_FLAG_IFF_UP; NET_SET_IF_VIF(&(if_vec[if_num].if_addr), NET_GET_IF_PHY_ADDR(&GET_IF(i)), vifs[vf].id); Clear_LL_Vector(if_num); if_num++; break; } } } } if (i == if_num) { log(LOG_ERR, 0,"VIF config error\n"); exit(-1); } } #ifdef USE_IPV6 else if (sock_type == RSRR_SOCK_V6UX) { if (rsrr_use_v2_ipv6) { /* * Use RSRR v2 format */ struct rsrr_vif *vifs; /* * skip over RSRR header */ vifs = (struct rsrr_vif *)(rsrr_recv_buf+RSRR_HEADER_LEN); /* * loop through all the interfaces from the * interface reply */ for (vf = 0; vf < rsrr_in->num; vf++) { /* * loop through the if_vec[] table we kept */ for (i = 0; i < lnum; i++) { /* * Skip over API interface */ if (IsNumAPI(i)) continue; if (((vifs[vf].family == AF_INET) && (vifs[vf].addr_v4.s_addr == NET_GET_ADDR_IPv4(&NET_GET_IF_PHY_ADDR(&GET_IF(i))).s_addr)) || ((vifs[vf].family == AF_INET6) && (SAME_IN6ADDR(vifs[vf].addr_v6, NET_GET_ADDR_IPv6(&NET_GET_IF_PHY_ADDR(&GET_IF(i))))))) { /* * fill out the table for doing conversion between * the interfaces used in gated and the ones used * in rsvpd */ gated_to_rsvpd[vifs[vf].id] = i; if (BIT_TST(vifs[vf].status,RSRR_M_DISABLED_BIT)) if_vec[i].if_flags &= ~IF_FLAG_IFF_UP; else if_vec[i].if_flags |= IF_FLAG_IFF_UP; break; } } } } else { /* * Gotta be an error */ log(LOG_ERR,0,"Only RSRRv2 supports IPv6",0); exit(-1); } } #endif /* USE_IPV6 */ return 0; } /* * Send a Route Query to routing for a dest-source pair. */ int rsrr_send_rq(pp, sp, af, src, dst, note) void *pp; /* PSB pointer */ void *sp; /* Session pointer */ u_char af; net_addr *src; net_addr *dst; int note; { struct rsrr_header *rsrr; int sendlen; int rv; /* * Set up Route Query message */ rsrr = (struct rsrr_header *) rsrr_send_buf; rsrr->type = RSRR_ROUTE_QUERY; rsrr->flags = 0; rsrr->num = 0; if (note) BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT); switch(af) { case AF_INET: if (rsrr_use_v1_ipv4) { /* * USE RSRR v1 */ struct rsrrv1_rq *route_query; rsrr->version = 1; route_query = (struct rsrrv1_rq *)(rsrr_send_buf + RSRR_HEADER_LEN); route_query->dest_addr = NET_GET_ADDR_IPv4(net_addr_ip(dst)); route_query->source_addr = NET_GET_ADDR_IPv4(net_addr_ip(src)); route_query->query_id = rsrr_qt_getid(pp); /* * Get the message size. */ sendlen = RSRRV1_RQ_LEN; if (IsDebug(DEBUG_RSRR)) { log(LOG_DEBUG, 0, "> Route Query (%s %s) Notify= %d\n", inet_fmt(route_query->source_addr.s_addr,s1), inet_fmt(route_query->dest_addr.s_addr,s2), BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); } /* * Send it. */ if (rsrr_send(RSRR_SOCK_V4UX,sendlen) >= 0) { /* * Cache the query if note is not zero, otherwise it is * only used to remove the route from route change * notification list in the daemon. */ if (note) rsrr_qt_cache(route_query->query_id,pp,sp,src,dst); /* * asynchronous route query/reply * return the query ID */ return route_query->query_id; } else return -1; } else if (rsrr_use_v2_ipv4) { /* * USE RSRR v2 */ struct rsrr_rq *route_query; rsrr->version = 2; route_query = (struct rsrr_rq *)(rsrr_send_buf + RSRR_HEADER_LEN); route_query->family = (u_short) AF_INET; route_query->length = (u_short) sizeof (struct in_addr); route_query->dst_v4 = NET_GET_ADDR_IPv4(net_addr_ip(dst)); route_query->src_v4 = NET_GET_ADDR_IPv4(net_addr_ip(src)); route_query->query_id = rsrr_qt_getid(pp); /* * Get the message size. */ sendlen = RSRR_RQ_LEN; if (IsDebug(DEBUG_RSRR)) { log(LOG_DEBUG, 0, "> Route Query (%s %s) Notify= %d\n", inet_fmt(route_query->src_v4.s_addr,s1), inet_fmt(route_query->dst_v4.s_addr,s2), BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); } /* * Send it. */ if (rsrr_send(RSRR_SOCK_V4UX,sendlen) >= 0) { /* * Cache the query if note is not zero, otherwise it is * only used to remove the route from route change * notification list in the daemon. */ if (note) rsrr_qt_cache(route_query->query_id,pp,sp,src,dst); /* * asynchronous route query/reply * return the query ID */ return route_query->query_id; } else return -1; } break; #ifdef USE_IPV6 case AF_INET6: if (rsrr_use_v2_ipv6) { /* * USE RSRR v2 */ struct rsrr_rq *route_query; rsrr->version = 2; route_query = (struct rsrr_rq *)(rsrr_send_buf + RSRR_HEADER_LEN); route_query->family = (u_short) AF_INET6; route_query->length = (u_short) sizeof (struct in6_addr); route_query->dst_v6 = NET_GET_ADDR_IPv6(net_addr_ip(dst)); route_query->src_v6 = NET_GET_ADDR_IPv6(net_addr_ip(src)); route_query->query_id = rsrr_qt_getid(pp); /* * Get the message size. */ sendlen = RSRR_RQ_LEN; if (IsDebug(DEBUG_RSRR)) { log(LOG_DEBUG, 0, "> Route Query (%s %s) Notify= %d\n", ip6_sprintf(&(route_query->src_v6)), ip6_sprintf(&(route_query->dst_v6)), BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); } /* * Send it. */ if (rsrr_send(RSRR_SOCK_V6UX,sendlen) >= 0) { /* * Cache the query if note is not zero, otherwise it is * only used to remove the route from route change * notification list in the daemon. */ if (note) rsrr_qt_cache(route_query->query_id,pp,sp,src,dst); /* * asynchronous route query/reply * return the query ID */ return route_query->query_id; } else return -1; } else if (rsrr_use_v1_ipv6) { /* * IPv6 and RSRRv1? Not possible */ log(LOG_ERR,0,"Only RSRRv2 supports IPv6"); rv = -1; } break; #endif /* USE_IPV6 */ default: log(LOG_ERR,errno,"No support for AF = %d",af); rv = -1; break; } return rv; } /* * Accept a Route Reply from routing. Find the related session and sender * structures and issue a PATH refresh if needed. */ int rsrr_accept_rr_ux(sock_type, rsrr) u_char sock_type; struct rsrr_header *rsrr; { net_addr src; net_addr dst; int rv; int in_lih; bitmap out_bmp; bitmap y; int note = 0; int shared = 0; int all_shared = 0; memset(s,0,sizeof(s)); bmp_rst(&out_bmp); bmp_rst(&y); if (sock_type == RSRR_SOCK_V4UX) { /* * IPv4 */ if (rsrr_use_v1_ipv4) { /* * RSRR v1 */ struct rsrrv1_rr *route_reply; route_reply=(struct rsrrv1_rr *)(rsrr_recv_buf+RSRR_HEADER_LEN); /* * IPv4 mrouted uses virtual interfaces, so we need to * shift the replying incoming interface and the outgoing * bitmap */ in_lih = route_reply->in_vif + shift; bmp_create(route_reply->out_vif_bm, &y); bmp_shift(&y, &out_bmp, shift); /* * Reject errors. */ if (BIT_TST(rsrr->flags,RSRR_ERROR_BIT)) { /* * Delete any associated cache entry so that we * can re-use the query id. */ rsrr_qt_delete(route_reply->query_id); if (IsDebug(DEBUG_RSRR)) log(LOG_DEBUG,0, "Rejecting Route Reply because Error bit set.\n"); return -1; } if (IsDebug(DEBUG_RSRR)) { log(LOG_DEBUG, 0, "< Route Reply (%s %s) in vif %d out vifs %s Notify= %d\n", inet_fmt(route_reply->source_addr.s_addr,s1), inet_fmt(route_reply->dest_addr.s_addr,s2), (u_char)(in_lih), bm_expand(&out_bmp, s), BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); } if (BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) note = 1; if (RSRR_USE_SHARED(rsrr->flags)) shared = 1; else if (RSRR_USE_ALL_SHARED(rsrr->flags)) all_shared = 1; NET_SET_ADDR_IPv4(&src,route_reply->source_addr); NET_SET_ADDR_IPv4(&dst,route_reply->dest_addr); rv = rsrr_route_reply(route_reply->query_id,&src,&dst, in_lih,(bitmap*)&(out_bmp), note, shared, all_shared); return rv; } else if (rsrr_use_v2_ipv4) { /* * RSRR v2 */ struct rsrr_rr *route_reply; route_reply = (struct rsrr_rr *)(rsrr_recv_buf + RSRR_HEADER_LEN); /* * IPv4 mrouted uses virtual interfaces, so we need to * shift the replying incoming interface and the outgoing * bitmap */ in_lih = route_reply->in_vif + shift; bmp_convert(&(route_reply->out_vif_bm), &y); bmp_shift(&y, &out_bmp, shift); /* * Reject errors. */ if (BIT_TST(rsrr->flags,RSRR_ERROR_BIT)) { /* * Delete any associated cache entry so that we * can re-use the query id. */ rsrr_qt_delete(route_reply->query_id); if (IsDebug(DEBUG_RSRR)) log(LOG_DEBUG,0, "Rejecting Route Reply because Error bit set.\n"); return -1; } if (IsDebug(DEBUG_RSRR)) { log(LOG_DEBUG, 0, "< Route Reply (%s %s) in vif %d out vifs %s Notify= %d\n", inet_fmt(route_reply->src_v4.s_addr,s1), inet_fmt(route_reply->dst_v4.s_addr,s2), (u_char)(in_lih), bm_expand(&out_bmp,s), BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); } if (BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) note = 1; if (RSRR_USE_SHARED(rsrr->flags)) shared = 1; else if (RSRR_USE_ALL_SHARED(rsrr->flags)) all_shared = 1; NET_SET_ADDR_IPv4(&src,route_reply->src_v4); NET_SET_ADDR_IPv4(&dst,route_reply->dst_v4); rv = rsrr_route_reply(route_reply->query_id,&src,&dst, in_lih, (bitmap *)&(out_bmp), note, shared, all_shared); return rv; } } #ifdef USE_IPV6 else if (sock_type == RSRR_SOCK_V6UX) { /* * IPv6 */ if (rsrr_use_v2_ipv6) { /* * RSRR v2 */ struct rsrr_rr *route_reply; rsrr_bmp tmpbmp; route_reply = (struct rsrr_rr *)(rsrr_recv_buf + RSRR_HEADER_LEN); /* * For IPv6 mrouting daemon, no virtual interface used, * but we need to do conversion between the interface * used in gated and the one used in rsvpd. The * gated_to_rsvpd[] table was set up during the * interface reply phase */ in_lih = gated_to_rsvpd[route_reply->in_vif]; convert(&(route_reply->out_vif_bm), &tmpbmp); bmp_convert(&tmpbmp, &out_bmp); /* * Reject errors. */ if (BIT_TST(rsrr->flags,RSRR_ERROR_BIT)) { /* * Delete any associated cache entry so that we * can re-use the query id. */ rsrr_qt_delete(route_reply->query_id); if (IsDebug(DEBUG_RSRR)) log(LOG_DEBUG,0, "Rejecting Route Reply because Error bit set.\n"); return -1; } if (IsDebug(DEBUG_RSRR)) { log(LOG_DEBUG, 0, "< Route Reply (%s %s) in vif %d out vifs %s Notify= %d\n", ip6_sprintf(&(route_reply->src_v6)), ip6_sprintf(&(route_reply->dst_v6)), (u_char)(in_lih), bm_expand(&out_bmp,s), BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); } if (BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) note = 1; if (RSRR_USE_SHARED(rsrr->flags)) shared = 1; else if (RSRR_USE_ALL_SHARED(rsrr->flags)) all_shared = 1; NET_SET_ADDR_IPv6(&src,route_reply->src_v6); NET_SET_ADDR_IPv6(&dst,route_reply->dst_v6); rv = rsrr_route_reply(route_reply->query_id,&src,&dst, in_lih, (bitmap *)&(out_bmp), note, shared, all_shared); return rv; } else if (rsrr_use_v1_ipv6) { /* * RSRRv1 and IPv6. Not possible */ log(LOG_ERR,0,"Only RSRRv2 supports IPv6"); return -1; } } #endif /* USE_IPV6 */ return 0; } /* * Initialize the query table. */ void rsrr_qt_init() { int i; for (i=0; iquery_id == query_id) { /* * We somehow managed to duplicate a query id. * Amazing! Ditch the old one. */ qt->query_id = query_id; qt->ptrP = pp; qt->ptrS = sp; qt->src = *src; qt->dst = *dst; return; } qt = qt->next; } /* * Cache entry doesn't already exist. Create one and insert at * front of list. */ qt = (struct rsrr_query_table *) malloc(sizeof(struct rsrr_query_table)); if (qt == NULL) { Log_Mem_Full("RSRR cache"); exit(-1); } qt->query_id = query_id; qt->ptrP = pp; qt->ptrS = sp; qt->src = *src; qt->dst = *dst; qt->next = rsrr_qt[hash]; rsrr_qt[hash] = qt; } /* * Lookup a query id in the table. */ struct rsrr_query_table * rsrr_qt_lookup(query_id) u_long query_id; { struct rsrr_query_table *qt; int hash = RSRR_QT_HASH(query_id); qt = rsrr_qt[hash]; while(qt) { if (qt->query_id == query_id) return qt; qt = qt->next; } return qt; } /* * Delete a query id from the table. */ void rsrr_qt_delete(query_id) u_long query_id; { struct rsrr_query_table *qt, *qt_prev; int hash = RSRR_QT_HASH(query_id); qt = rsrr_qt[hash]; while(qt) { if (qt->query_id == query_id) { if (qt == rsrr_qt[hash]) /* * Deleting first entry. */ rsrr_qt[hash] = qt->next; else qt_prev->next = qt->next; free(qt); return; } qt_prev = qt; qt = qt->next; } } void SetNotifyBit(psbp, note) PSB *psbp; int note; { if (note) /* * Routing can do route change notification. Set bit in * sender structure that indicates RSRR no longer needs to * send queries. */ BIT_SET(psbp->ps_rsrr_flags, PSBF_RSRR_NOTIFY); else /* * Clear the bit just in case it was set. */ BIT_CLR(psbp->ps_rsrr_flags, PSBF_RSRR_NOTIFY); } #endif /* ! HOST_ONLY */ /* * The interface list in gated is different from the one being used in * rsvpd, thus we need to do some conversion for the bitmap returned * from gated to the one in rsvpd. For example, the interface table * in gated includes loop-back interfaces, and it has different ordering * for the interfaces of the same physical interface. We have built a * conversion table gated_to_rsvpd[] during interface reply, now we * use it to do the conversion. */ rsrr_bmp * convert(rsrr_bmp *x, rsrr_bmp *y) { int i,j,d,m; for (i=0; i<(RSRR_MAX_VIFS_V2/NBBY); i++) y->bm[i]=0; for (i=0; ibm[d]) & (1<bm[d] |= (1 << m); } } return y; }