/* * @(#) $Id: rsvp_netio.c,v 4.48 1998/08/12 00:26:39 kann Exp $ */ /************************ rsvp_netio.c ****************************** * * * Network I/O routines * * * *********************************************************************/ /**************************************************************************** RSVPD -- ReSerVation Protocol Daemon USC Information Sciences Institute Marina del Rey, California Original Version: Shai Herzog, Nov. 1993. Current Version: Steven Berson & Bob Braden, May 1996. 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 "rsvp_api.h" #include "rapi_lib.h" #include #include #if (defined(SOLARIS) && defined(USE_IPV6)) struct ip6_hdr { union { struct ip6_hdrctl { u_int32_t ip6_un1_flow; /* 24 bits of flow-ID */ u_int16_t ip6_un1_plen; /* payload length */ u_int8_t ip6_un1_nxt; /* next header */ u_int8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; u_int8_t ip6_un2_vfc; /* 4 bits version, 4 bits priority */ } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ }; #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim #endif /* (defined(SOLARIS) && defined(USE_IPV6)) */ #if (defined(freebsd) && defined(USE_IPV6)) #define STEVENS_API #include #endif /* (defined(freebsd) && defined(USE_IPV6)) */ #define UCAST_TTL 63 /* Sockets and addresses */ struct in_addr encap_group; /* Gu */ u_int16_t encap_port; /* Pu */ u_int16_t encap_portp; /* Pu' */ net_addr *encap_router; net_addr encap_mc_addr; #ifdef USE_IPV6 struct in6_addr encap_group6; /* Gu */ net_addr encap_mc_addr6; #endif /* USE_IPV6 */ /* External declarations */ extern char *Type_name[]; extern int Test_mode; extern net_addr *tsttun_vec; extern int shift; extern int bmptoif(bitmap *); extern int rsrr_route_query(void*,void *,net_addr *,net_addr *,int,int *,bitmap *); /* forward declarations */ static int send_pkt(net_addr *to,net_addr *from,void *msg,int len, int vif,int infn,int hops,int ra); static int IsLocal(net_addr *,int *); static net_addr * udp_addr(net_addr *to,int port); static net_addr * encap_addr(net_addr *to); static int rsvp_pkt_process_1(struct packet *, net_addr *, int); static int udp_input(net_addr *from,char *msg,int len,net_if *inf); static int consume_input(struct packet *packet,net_addr *from,net_if *inf); static int raw_input_ipv4(net_addr *from,char *msg,int len,net_if *inf); #ifdef USE_IPV6 static int raw_input_ipv6(net_addr *from,char *msg,int len,net_if *inf); #endif /* USE_IPV6 */ /* * send_pkt_out_if(): Send (unicast) RSVP packet to specified previous * hop via specified physical interface (or -1). * * [The outgoing interface is not strictly required to send * unicast messages, but do need it to choose encryption key.] */ int send_pkt_out_if( int outif, RSVP_HOP *hopp, struct packet *pkt) { net_addr *to; net_addr *src = NULL; int mode = 0; assert(!IsHopAPI(hopp)); to = hop_addr(hopp); pkt->pkt_ttl = UCAST_TTL; if (outif >= 0) src = get_if(outif); Incr_ifstats(outif, rsvpstat_msgs_out[pkt->pkt_map->rsvp_msgtype]); mode = build_send_pkt(outif, to, src, pkt); if (IsDebug(DEBUG_ALL)) { char tmp[32]; if (outif >= 0) sprintf(tmp, "%d=>%s > %.16s/%d\n", outif, IF_NAME(outif), net_addr_host(to), pkt->pkt_ttl); else sprintf(tmp, "> %.16s/%d\n", net_addr_host(to), pkt->pkt_ttl); log_event(LOGEV_Send_UDP+mode-1, Type_name[pkt->pkt_map->rsvp_msgtype], pkt->pkt_map->rsvp_session, tmp); if (IsDebug(DEBUG_IO)) print_rsvp(pkt); } return(0); } /* * send_pkt_to(): * Send an RSVP packet to specified inet_addr:port entity. * This is typically used for UDP diagnostics. * Rsvptrace uses this to send UDP DREQ packets. * outif is typically -1. For multicast destinations, it has * the usual meaning. */ int send_pkt_to( int outif, net_addr *toaddr, struct packet *pkt) { net_addr *srcaddrp = NULL; int mode = 0; switch(NET_GET_TYPE(toaddr)) { case NET_ADDR_UDP_IPv4: assert((NET_GET_ADDR_IPv4(toaddr)).s_addr != INADDR_ANY); assert((NET_GET_ADDR_UDP_IPv4(toaddr)).sin_port != 0); /* TTL setup is only for unicast packets. If this was a diagnostics reply to * a multicast address, ttl would have already been set. */ if(!IN_IS_ADDR_MULTICAST(&NET_GET_ADDR_IPv4(toaddr))) pkt->pkt_ttl = UCAST_TTL; if (outif >= 0) srcaddrp = get_if(outif); break ; case NET_ADDR_UDP_IPv6: /* IPv6 is currently not yet expected to be used by diagnostics */ break ; default: break ; } /* The PKTFLG_NOENCAP helps override the RSVP UDP encapsulation rules * for the diagnostics reply scenario. In this case, a UDP DREP has to * be sent to the diagnostic requester's ephemeral UDP port */ pkt->pkt_flags |= PKTFLG_NOENCAP ; Incr_ifstats(outif, rsvpstat_msgs_out[pkt->pkt_map->rsvp_msgtype]); mode = build_send_pkt(outif, toaddr, srcaddrp, pkt); if (IsDebug(DEBUG_ALL)) { char tmp[32]; if (outif >= 0) sprintf(tmp, "%d> %.16s/%d\n", outif, net_addr_host(toaddr), pkt->pkt_ttl); else sprintf(tmp, "> %.16s/%d\n", net_addr_host(toaddr), pkt->pkt_ttl); log_event(LOGEV_Send_UDP+mode-1, Type_name[pkt->pkt_map->rsvp_msgtype], pkt->pkt_map->rsvp_session, tmp); if (IsDebug(DEBUG_IO)) print_rsvp(pkt); } if (mode < 0) return(-1) ; return(0); } /* * send_pkt_out_vif(): Send Path, PathTear, or ResvErr msg with specific * dest and src addresses to specified vif. * * XXX??? If encap_router address is defined, unicast a unicast UDP * XXX??? copy to that address; this is to allow hosts inside a * XXX??? firewall to send a Path message to the first-hop router. */ int send_pkt_out_vif( int vif, Session *destp, FILTER_SPEC *filtp, struct packet *pkt) { net_addr *to; net_addr *src; int mode = 0; #ifdef EX_ROUTE EX_ROUTE_IPv4 *ex_routep; u_long netmask; #endif assert(!IsNumAPI(vif)); /* Not API */ src = filterspec_addr(filtp); #ifdef EX_ROUTE /* * If there is an EXROUTE object the to address is set to the addres specified in * in the object. */ if (pkt->pkt_map->rsvp_exroute != NULL){ if (Obj_Length(pkt->pkt_map->rsvp_exroute) != 0){ log(LOG_DEBUG, 0, "Route Object ????????!!!!!!!!!!!!\n"); ex_routep = (EX_ROUTE_IPv4 *)((char *)pkt->pkt_map->rsvp_exroute+4); to = malloc(sizeof(net_addr)); to->type = NET_ADDR_IPv4; if(ex_routep->rprefix != 0) { netmask = prefix_to_mask(ex_routep->rprefix); to->u.addr_ipv4.s_addr = ((ex_routep->ipv4_addr2 << 16) | (ex_routep->ipv4_addr1)) & htonl(netmask); } else to->u.addr_ipv4.s_addr = (ex_routep->ipv4_addr2 << 16) | (ex_routep->ipv4_addr1); } else to = session_addr(destp->d_session); } else to = session_addr(destp->d_session); #else to = session_addr(destp->d_session); #endif if (encap_router != NULL) { /* If a -R cmd-line option was given to specify the address * of an RSVP-capable router, unicast a UDP copy of pkt to * address. Note: this could be generalized to a list. */ pkt->pkt_flags = PKTFLG_USE_UDP; } Incr_ifstats(vif, rsvpstat_msgs_out[pkt->pkt_map->rsvp_msgtype]); mode = build_send_pkt(vif, to, src, pkt); if (mode < 0) return -1; if (IsDebug(DEBUG_ALL)) { char tmp[32]; sprintf(tmp, "%d=>%s > %.16s/%d\n", vif, IF_NAME(vif), net_addr_host(to), pkt->pkt_ttl); log_event(LOGEV_Send_UDP+mode-1, Type_name[pkt->pkt_map->rsvp_msgtype], pkt->pkt_map->rsvp_session, tmp); if (IsDebug(DEBUG_IO)) print_rsvp(pkt); } return(0); } /* * do_sendmsg(): Send buffer containing RSVP message: * * To specified vif; -1 => unspecified (Resv msgs) * * To destination (addr,port) = *to * * From IP source address = *src; NULL => unspecified * * tp specified TTL (unless UDP encaps is used) * * This routine figures out whether UDP and/or raw encapsualated copies * are needed, and chooses the appropriate socket. The socket choice * is quite system-dependent. */ int do_sendmsg( int vif, net_addr *to, net_addr *src, int flags, u_char ttl, u_char *data, int len) { u_char encap_ttl; int mc,local,mode = 0; net_addr *addr; local = IsLocal(to,&mc); if (vif >= 0) { if (!(IF_FLAGS(vif)&IF_FLAG_IFF_UP)) return(0); /* Should never happen? */ if (mc && !(IF_FLAGS(vif)&IF_FLAG_IFF_MC)) return(0); /* Should never happen? */ encap_ttl = if_vec[IF_UNICAST(vif)].if_udpttl; } else encap_ttl = RSVP_TTL_MAX; if (flags & PKTFLG_NOENCAP) { /* send packet to a UDP target with a port that is not Pu or Pu' */ if (mc) encap_ttl = ttl ; if (FAILED(send_pkt(to,src,data,len,mc,vif,encap_ttl,FALSE))) log(LOG_ERR,errno,"send_pkt"); return(1); } if (!net_has_rawmode()) { /* UDP-only host. */ if (mc) { /* Multicast Path msg: => (G*, P) */ addr = encap_addr(to); } else if (vif >= 0 && !local) { /* Unicast Path msg to non-local D => (Ra, Pu) */ if (encap_router == NULL) { log(LOG_ERR,0, "No UDP Encapsulation Router (Ra)"); return(0); } addr = udp_addr(encap_router,encap_port); } else { /* Unicast Path/Resv msg to local D => (D, Pu) */ addr = udp_addr(to,encap_port); } if (FAILED(send_pkt(addr,src,data,len,mc,vif, encap_ttl,FALSE))) log(LOG_ERR,errno,"send_pkt"); return(1); } else { /* * Send raw encapsulation */ if (mc && (vif > shift) && (ttl < vif_list[if_vec[vif].if_index].threshold)) { /* * if it's multicast packet, and vif * is in the virtual interface space, * also the ttl value is less than the * threshold value for that virtual * interface, then we drop the packet * and return */ Incr_ifstats(vif, rsvpstat_path_threshold); return (0); } if (FAILED(send_pkt(to,src,data,len,mc,vif,ttl, (flags & PKTFLG_Send_RA)))) log(LOG_ERR,errno,"send_pkt"); mode = 2; } if (((vif >= 0 && (IF_FLAGS(vif) & IF_FLAG_UseUDP)) || (flags & PKTFLG_USE_UDP)) && local) { /* * Need UDP encapsulation on this interface, but * we are capable of sending raw packets => (D, Pu') */ if (FAILED(send_pkt(udp_addr(to,encap_portp),src,data,len, mc,vif,encap_ttl,FALSE))) log(LOG_ERR,errno,"send_pkt"); return(mode + 1); } return(mode); } static int send_pkt(net_addr *to,net_addr *from,void *msg,int len, int mc,int infn,int hops,int ra) { net_addr src; net_if inf; if (from != NULL) { switch (NET_GET_TYPE(from)) { case NET_ADDR_IPv4: if (NET_GET_TYPE(to) == NET_ADDR_UDP_IPv4) { NET_SET_ADDR3_UDP_IPv4(&src, NET_GET_ADDR_IPv4(from), encap_port); from = &src; } break; #ifdef USE_IPV6 case NET_ADDR_IPv6: if (NET_GET_TYPE(to) == NET_ADDR_UDP_IPv6) { NET_SET_ADDR3_UDP_IPv6(&src, NET_GET_ADDR_IPv6(from), encap_port); from = &src; } break; #endif /* USE_IPV6 */ default: break; } } if (l_debug >= LOG_HEXD) { log(LOG_DEBUG, 0, "Output to %s\n", net_addr_print(to)); hexf(stderr, msg, len); } if (infn < 0) return(net_send(to,from,msg,len,NULL,hops,ra)); if (mc) inf = if_vec[infn].if_addr; else inf = if_vec[IF_UNICAST(infn)].if_addr; return(net_send(to,from,msg,len,&inf,hops,ra)); } static int IsLocal(net_addr *addr,int *mc) { int i,j; net_addr *x,*y; net_if *inf; struct in_addr a,b; #ifdef USE_IPV6 struct in6_addr c,d; #endif /* USE_IPV6 */ x = net_addr_ip(addr); *mc = FALSE; switch (NET_GET_TYPE(x)) { case NET_ADDR_IPv4: a = NET_GET_ADDR_IPv4(x); if (IN_IS_ADDR_MULTICAST(&a)) { *mc = TRUE; return(TRUE); } for (i = 0; i < if_num; i++) { if (IsNumAPI(i)) continue; if (IF_DOWN(i)) continue; inf = &GET_IF(i); if (NET_GET_TYPE(inf) != NET_IF_PHY) continue; y = &NET_GET_IF_PHY_ADDR(inf); if (NET_UNEQUAL_TYPE(x,y)) continue; b = NET_GET_ADDR_IPv4(y); for (j = if_vec[i].prefix;j < NBITS(a);j++) { BSET_CLR(j,&a); BSET_CLR(j,&b); } if (IN_ARE_ADDR_EQUAL(&a,&b)) return(TRUE); } break; #ifdef USE_IPV6 case NET_ADDR_IPv6: c = NET_GET_ADDR_IPv6(x); if (IN6_IS_ADDR_MULTICAST(&c)) { *mc = TRUE; return(TRUE); } for (i = 0; i < if_num; i++) { if (IsNumAPI(i)) continue; if (IF_DOWN(i)) continue; inf = &GET_IF(i); if (NET_GET_TYPE(inf) != NET_IF_PHY) continue; y = &NET_GET_IF_PHY_ADDR(inf); if (NET_UNEQUAL_TYPE(x,y)) continue; d = NET_GET_ADDR_IPv6(y); for (j = if_vec[i].prefix;j < NBITS(c);j++) { BSET_CLR(j,&c); BSET_CLR(j,&d); } if (IN6_ARE_ADDR_EQUAL(&c,&d)) return(TRUE); } break; #endif /* USE_IPV6 */ default: break; } return(FALSE); } static net_addr * encap_addr(net_addr *to) { switch (NET_GET_TYPE(to)) { case NET_ADDR_IPv4: case NET_ADDR_UDP_IPv4: return(&encap_mc_addr); #ifdef USE_IPV6 case NET_ADDR_IPv6: case NET_ADDR_UDP_IPv6: return(&encap_mc_addr6); #endif /* USE_IPV6 */ default: return(NULL); } } static net_addr * udp_addr(net_addr *to,int port) { static net_addr addr; switch (NET_GET_TYPE(to)) { case NET_ADDR_IPv4: NET_SET_ADDR3_UDP_IPv4(&addr, NET_GET_ADDR_IPv4(to),port); return(&addr); case NET_ADDR_UDP_IPv4: NET_SET_ADDR3_UDP_IPv4(&addr, NET_GET_ADDR_UDP_IPv4(to).sin_addr,port); return(&addr); #ifdef USE_IPV6 case NET_ADDR_IPv6: NET_SET_ADDR3_UDP_IPv6(&addr, NET_GET_ADDR_IPv6(to),port); return(&addr); case NET_ADDR_UDP_IPv6: NET_SET_ADDR3_UDP_IPv6(&addr, NET_GET_ADDR_UDP_IPv6(to).sin6_addr,port); return(&addr); #endif /* USE_IPV6 */ default: return(NULL); } } int rsvp_input(int fd) { int n; char msg[MAX_PKT + sizeof(struct ip)]; net_addr from; net_if inf; n = net_recv(&from,msg,sizeof(msg),&inf); if (n == 0) return(FALSE); if (FAILED(n)) { log(LOG_ERR,errno,"net_recv"); return(FALSE); } switch(NET_GET_TYPE(&from)) { case NET_ADDR_IPv4: raw_input_ipv4(&from,msg,n,&inf); break; case NET_ADDR_UDP_IPv4: case NET_ADDR_UDP_IPv6: udp_input(&from,msg,n,&inf); break; #ifdef USE_IPV6 case NET_ADDR_IPv6: raw_input_ipv6(&from,msg,n,&inf); break; #endif /* USE_IPV6 */ default: log(LOG_ERR,errno,"net_recv"); return(FALSE); } return(TRUE); } /* * raw_input(): receive an RSVP protocol message (protocol 46) */ static int raw_input_ipv4(net_addr *from,char *msg,int len,net_if *inf) { net_addr dst,src; struct ip *ip = (struct ip *) msg; int iphdrlen, ipdatalen; struct packet packet; struct { packet_map raw_map_base; union { SenderDesc Sender_list; /* For Path-like messages */ FlowDesc Resv_list; /* For Resv-like messages */ } raw_map_ext[MAX_FLWDS-1]; } map; #ifdef __alpha__ iphdrlen = (ip->ip_vhl & 0xf) << 2; #else iphdrlen = ip->ip_hl << 2; #endif ipdatalen = ip->ip_len; if (iphdrlen + ipdatalen != len) { log(LOG_ERR, 0, "Packet length wrong", 0); return(-1); } packet.pkt_order = BO_NET; packet.pkt_len = ipdatalen; packet.pkt_data = (common_header *) &msg[iphdrlen]; packet.pkt_offset = 0; packet.pkt_map = (packet_map *) ↦ packet.pkt_flags = 0; packet.pkt_ttl = ip->ip_ttl; /* * If dest addr is multicast group, test for and drop the * packet if we sent it ourselves. This "accidental" loopback * can only happen if there is an application running on this * (router) node, which has joined this multicast group; then * multicast Path, etc messages send to vifs will be * received on socket using RSVP_ON. */ NET_SET_ADDR_IPv4(&dst,ip->ip_dst); if (IN_IS_ADDR_MULTICAST(&ip->ip_dst)) { NET_SET_ADDR_IPv4(&src,ip->ip_src); if (map_if_addr(&src) != -1) return(SYS_NOERROR); } /* Unicast dest in IP header: map into apparent local * interface number, to be sure it was for me. */ else if (map_if_addr(&dst) < 0) { /* * If the message type is not Path or PathTear or ResvConf and if * IP destination address does not match any of the * addresses of the local interfaces, then forward the * message to IP destination address and return. */ if (packet.pkt_data->rsvp_type != RSVP_PATH && packet.pkt_data->rsvp_type != RSVP_CONFIRM && packet.pkt_data->rsvp_type != RSVP_PATH_TEAR) { if (FAILED(net_send(&dst,NULL,&msg[iphdrlen],ipdatalen, NULL,ip->ip_ttl,FALSE))) { log(LOG_ERR,errno,"net_send"); return(SYS_ERROR); } return(SYS_NOERROR); } } /* * Call common routine to do initial processing of RSVP packet. */ return(consume_input(&packet, from, inf)); } #ifdef USE_IPV6 static int raw_input_ipv6(net_addr *from,char *msg,int len,net_if *inf) { net_addr dst,src; struct ip6_hdr *ip = (struct ip6_hdr *) msg; int ipdatalen; int iphdrlen = sizeof(struct ip6_hdr); struct packet packet; struct { packet_map raw_map_base; union { SenderDesc Sender_list; /* For Path-like messages */ FlowDesc Resv_list; /* For Resv-like messages */ } raw_map_ext[MAX_FLWDS-1]; } map; ipdatalen = ip->ip6_plen; if (iphdrlen + ipdatalen != len) { log(LOG_ERR, 0, "Packet length wrong", 0); return(-1); } packet.pkt_order = BO_NET; packet.pkt_len = ipdatalen; packet.pkt_data = (common_header *) &msg[iphdrlen]; packet.pkt_offset = 0; packet.pkt_map = (packet_map *) ↦ packet.pkt_flags = 0; packet.pkt_ttl = ip->ip6_hlim; /* * If dest addr is multicast group, test for and drop the * packet if we sent it ourselves. This "accidental" loopback * can only happen if there is an application running on this * (router) node, which has joined this multicast group; then * multicast Path, etc messages send to vifs will be * received on socket using RSVP_ON. */ NET_SET_ADDR_IPv6(&dst,ip->ip6_dst); if (IN6_IS_ADDR_MULTICAST(&ip->ip6_dst)) { NET_SET_ADDR_IPv6(&src,ip->ip6_src); if (map_if_addr(&src) != -1) return(SYS_NOERROR); } /* Unicast dest in IP header: map into apparent local * interface number, to be sure it was for me. */ else if (map_if_addr(&dst) < 0) { /* * If the message type is not Path or PathTear or ResvConf and if * IP destination address does not match any of the * addresses of the local interfaces, then forward the * message to IP destination address and return. */ if (packet.pkt_data->rsvp_type != RSVP_PATH && packet.pkt_data->rsvp_type != RSVP_CONFIRM && packet.pkt_data->rsvp_type != RSVP_PATH_TEAR) { if (FAILED(net_send(&dst,NULL,&msg[iphdrlen],ipdatalen, NULL,ip->ip6_hlim,FALSE))) { log(LOG_ERR,errno,"net_send"); return(SYS_ERROR); } return(SYS_NOERROR); } } /* * Call common routine to do initial processing of RSVP packet. */ return(consume_input(&packet, from, inf)); } #endif /* USE_IPV6 */ /* * udp_input(): receive a UDP-encapsulated RSVP protocol message */ static int udp_input(net_addr *from,char *msg,int len,net_if *inf) { struct packet packet; struct { packet_map raw_map_base; union { SenderDesc Sender_list; /* For Path-like messages */ FlowDesc Resv_list; /* For Resv-like messages */ } raw_map_ext[MAX_FLWDS-1]; } map; packet.pkt_order = BO_NET; packet.pkt_len = len; packet.pkt_data = (common_header *) msg; packet.pkt_offset = 0; packet.pkt_map = (packet_map *) ↦ packet.pkt_flags = PKTFLG_USE_UDP; packet.pkt_ttl = packet.pkt_data->rsvp_snd_TTL; if (Test_mode) { int i; net_addr *addr; addr = net_addr_ip(from); for (i= 0; i = LOG_HEXD) { log(LOG_DEBUG, 0, "Raw input from %s on vif %d\n", net_addr_print(from),vif); hexf(stderr, (char *)packet->pkt_data, packet->pkt_len); } rc = rsvp_pkt_process(packet, from, vif); if (rc < 0) { log(LOG_WARNING, 0, "\n%s Parse error %d in raw pkt from %s\n", rsvp_timestamp(), rc, net_addr_print(from)); hexf(stdout, (char *)packet->pkt_data, packet->pkt_len); } return(rc); } /* * rsvp_pkt_process(): Primary RSVP protocol processing routine for input. * Called with either a new packet received from the * network, or a stored packet from the API. */ int rsvp_pkt_process( struct packet *pkt, /* packet struct. Flags => UDP|raw */ net_addr *fromp, /* Addr(src IP addr) or NULL (API) */ int inp_if) /* Incoming interface (-1 => mcast) */ { int rerrno = PKT_OK; packet_map *mapp = pkt->pkt_map; int Not_from_API = (fromp)?1:0; rerrno = rsvp_pkt_map(pkt); if (IsDebug(DEBUG_ALL)) { char temp[32]; int evtype; if (Not_from_API) { if (inp_if < 0) sprintf(temp, "< %.16s", net_addr_host(fromp)); else sprintf(temp, "%s<=%d < %.16s", IF_NAME(inp_if), inp_if, net_addr_host(fromp)); evtype = (pkt->pkt_flags&PKTFLG_USE_UDP)? LOGEV_Recv_UDP:LOGEV_Recv_Raw; } else { sprintf(temp, "pkt_ttl); if (IsDebug(DEBUG_IO)) { print_rsvp(pkt); } } } if (rerrno > 0) { /* Packet contains object with unknown class, * and high-order bits of class number indicate * that packet should be rejected and error * message sent. */ if (!(mapp->rsvp_hop)||!(mapp->rsvp_session)) /* No HOP or no SESSION... can't send err message. */ return(rerrno); switch (mapp->rsvp_msgtype) { case RSVP_PATH: rsvp_path_err(inp_if, Get_Errcode(rerrno), Get_Errval(rerrno), pkt); break; case RSVP_RESV: rsvp_resv_err(Get_Errcode(rerrno), Get_Errval(rerrno), 0, (FiltSpecStar *) -1, pkt); break; default: /* Spec says don't send error for Teardown msg */ /* Spec says don't send error for error msg */ break; } } if (rerrno == PKT_OK) rerrno = rsvp_pkt_process_1(pkt, fromp, inp_if); return(rerrno); } /* Inner routine for rsvp_pkt_process() */ static int rsvp_pkt_process_1( struct packet *pkt, /* packet struct. Flags => UDP|raw */ net_addr *fromp, /* Addr(src IP addr) or NULL (API) */ int inp_if) /* Incoming interface (-1 => mcast) */ { packet_map *mapp = pkt->pkt_map; int Not_from_API = (fromp)?1:0; int i, rc; int rv; bitmap bmp; bmp_rst(&bmp); /* If there is a hop address and it's not from API, hop address * must be non-zero. */ if ((Not_from_API) && (pkt->pkt_map->rsvp_hop) && IsHopAPI(pkt->rsvp_phop)) return PKT_ERR_HOPZERO; /* * For each msg type, do format checking and various other * checks, then call appropriate handling routine. */ rc = 0; switch (mapp->rsvp_msgtype) { #ifdef RSVP_DIAGS case (RSVP_DREQ): /* If this was an incoming DREQ from the client, it will have the UDP flag set. * we disable it */ pkt->pkt_flags &= ~(PKTFLG_USE_UDP); rc = accept_diag_request(inp_if, pkt, fromp); break; case (RSVP_DREP): rc = accept_diag_reply(inp_if, pkt); break; #endif /* defined RSVP_DIAGS */ case (RSVP_PATH): /* If number of sender descriptors is zero, * ignore the message. This case is a (deliberate) * wierdness of the Version 1 RSVP spec. * XXX Should we log or count these anomalies ? */ if (pkt->rsvp_nflwd == 0) return PKT_OK; /* Wierdness */ if (!(mapp->rsvp_hop)||!(mapp->rsvp_timev)) return PKT_ERR_MISSOBJ; if (!(mapp->rsvp_list[0].Sender_list.rsvp_stempl) || !(mapp->rsvp_list[0].Sender_list.rsvp_stspec) ) return PKT_ERR_MISSOBJ; if (pkt->pkt_ttl == 0) return PKT_ERR_TTLZERO; /* * If the DstPort in the SESSION object is zero * but SrcPort in SENDER_TEMPLATE is non-zero, * return "Bad Src Ports" (neighbor) error. */ if (session_get_port(pkt->rsvp_sess) == 0 && filterspec_port(STempl_of(SenderDesc_of(pkt))) != 0) return PKT_ERR_BADSPORT; /* Multihomed host without mrouted: cannot tell the incoming * interface on which a multicast Path message really arrived * under SunOS (or probably any system derived from 4.3 BSD). * It would assume default (if# 0); then when send Resv msg, * may attach wrong NHOP address. First try mapping destination * address into one of our interfaces. If that fails, use kludge: * do unicast route lookup and use resulting interface addr. * THIS ASSUMES UNICAST ROUTING IN THE OTHER DIRECTION MATCHES * MULTICAST ROUTING, and that vif's are a subset of if's. */ #define TYPE_V4(x) ((x == ctype_SESSION_ipv4) || (x == ctype_SESSION_ipv4GPI)) #ifdef USE_IPV6 #define TYPE_V6(x) ((x == ctype_SESSION_ipv6) || (x == ctype_SESSION_ipv6GPI)) #endif /* USE_IPV6 */ if (inp_if < 0 && if_num > 2) { inp_if = session_if(pkt->rsvp_sess); if (inp_if < 0) { /* inp_if = unicast_route(hop_addr(pkt->rsvp_phop)); */ rv = rsrr_route_query((void *)0, (void *)0, (net_addr *)0, hop_addr(pkt->rsvp_phop), 0, (int *)0, &bmp); if (rv == -1) { /* log(LOG_ERR,errno,"Unicast route lookup failure"); */ if (TYPE_V4(Obj_CType(pkt->rsvp_sess))) { inp_if = local_v4; } #ifdef USE_IPV6 else if (TYPE_V6(Obj_CType(pkt->rsvp_sess))) { inp_if = local_v6; } #endif /* USE_IPV6 */ } else inp_if = bmptoif(&bmp); if (inp_if < 0) { log(LOG_WARNING, 0, "No inc iface\n"); return(PKT_OK); /* XXX Not OK */ } } } if ((inp_if >=0 && inp_if < api_num) && session_multicast(pkt->rsvp_sess) && !NoV4Mroute && TYPE_V4(Obj_CType(pkt->rsvp_sess))) { inp_if += shift; } rc = accept_path(inp_if, pkt); break; case (RSVP_RESV): /* If number of flow descriptors is zero, * ignore the message. This case is a (deliberate) * wierdness of the Version 1 RSVP spec. * XXX Should we log or count these anomalies ? */ if (pkt->rsvp_nflwd == 0) return PKT_OK; /* Wierdness */ #ifdef DEBUG /* Nhop address should be normally be identical * to IP src addr, but non-RSVP clouds can do * funny things... */ if ((Not_from_API) && !net_addr_equal(net_addr_ip(fromp), hop_addr(pkt->rsvp_nhop))) log(LOG_WARNING, 0, "Nhop != IP src in Resv\n"); #endif /* DEBUG */ if (!(mapp->rsvp_style) || !(mapp->rsvp_hop)||!(mapp->rsvp_timev)) return PKT_ERR_MISSOBJ; /* * If the DstPort in the SESSION object is zero * but SrcPort in a FILTER_SPEC is non-zero, * return "Bad Src Ports" (neighbor) error. */ if (session_get_port(pkt->rsvp_sess) == 0){ for (i =0; i < pkt->rsvp_nflwd ; i++) { FILTER_SPEC *filtp = filter_of(FlowDesc_of(pkt,i)); if (filtp && filterspec_port(filtp) != 0) return PKT_ERR_BADSPORT; } } /* * Check reasonableness of the LIH */ if (!IsHopAPI(pkt->rsvp_nhop) && hop_lih(pkt->rsvp_nhop) > if_num) return PKT_ERR_BADLIH; rc = accept_resv(inp_if, pkt); break; case (RSVP_PATH_TEAR): if (pkt->rsvp_nflwd == 0) return PKT_OK; /* Wierdness */ if (!(mapp->rsvp_hop)) return PKT_ERR_MISSOBJ; mapp->rsvp_timev = NULL; /* ignore TIMEV */ if ((inp_if >=0 && inp_if < api_num) && session_multicast(pkt->rsvp_sess) && !NoV4Mroute && TYPE_V4(Obj_CType(pkt->rsvp_sess))) { inp_if += shift; } rc = accept_path_tear(inp_if, pkt); break; case (RSVP_PATH_ERR): if (pkt->rsvp_nflwd == 0) return PKT_OK; /* Wierdness */ if (!(mapp->rsvp_errspec) ) return PKT_ERR_MISSOBJ; mapp->rsvp_timev = NULL; /* ignore TIMEV */ if ((inp_if >=0 && inp_if < api_num) && session_multicast(pkt->rsvp_sess) && !NoV4Mroute && TYPE_V4(Obj_CType(pkt->rsvp_sess))) { inp_if += shift; } rc = accept_path_err(inp_if, pkt); break; case (RSVP_RESV_TEAR): /* Note that a ResvTear can legitimately have no * flow descriptor, for WF style. */ if (!(mapp->rsvp_style) || !(mapp->rsvp_hop) ) return PKT_ERR_MISSOBJ; /* * Check reasonableness of the LIH */ if (!IsHopAPI(pkt->rsvp_nhop) && hop_lih(pkt->rsvp_nhop) > if_num) return PKT_ERR_BADLIH; mapp->rsvp_timev = NULL; /* ignore TIMEV */ rc = accept_resv_tear(inp_if, pkt); break; case (RSVP_RESV_ERR): if (pkt->rsvp_nflwd == 0) return PKT_OK; /* Wierdness */ if (!(mapp->rsvp_style) || !(mapp->rsvp_errspec) || !(mapp->rsvp_hop) ) return PKT_ERR_MISSOBJ; mapp->rsvp_timev = NULL; /* ignore TIMEV */ rc = accept_resv_err(inp_if, pkt); break; case (RSVP_CONFIRM): if (!(mapp->rsvp_style) || !(mapp->rsvp_errspec) || !(mapp->rsvp_confirm)) return PKT_ERR_MISSOBJ; mapp->rsvp_timev = NULL; /* ignore TIMEV */ rc = accept_resv_conf(inp_if, pkt); break; default: return PKT_ERR_MSGTYPE; } if (rc < -1) return rc; return PKT_OK; }