/* * @(#) $Id: rsvp_trans.c,v 4.41 1998/08/13 15:37:44 kann Exp $ */ /*********************** rsvp_trans.c ******************************** * * * System Independent Interface to Network and Transport Layers * * * *********************************************************************/ /**************************************************************************** RSVPD -- ReSerVation Protocol Daemon USC Information Sciences Institute Marina del Rey, California Original Version: Shai Herzog, Nov. 1993. Current Version: Bob Lindell, July 1997. Copyright (c) 1997 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #endif /* __FreeBSD__ */ #include "rsvp_socks.h" #include "rsvp_trans.h" #ifndef IPPROTO_RSVP #define IPPROTO_RSVP 46 #endif /* IPPROTO_RSVP */ #ifdef SO_REUSEPORT #define SO_REUSEXXXX SO_REUSEPORT #else /* SO_REUSEPORT */ #define SO_REUSEXXXX SO_REUSEADDR #endif /* SO_REUSEPORT */ #ifdef sun #if (defined(__SVR4) || defined(__svr4__)) #define SOLARIS #else /* (defined(__SVR4) || defined(__svr4__)) */ #define SunOS #endif /* (defined(__SVR4) || defined(__svr4__)) */ #endif /* sun */ #ifdef SunOS extern int ioctl(int,int,caddr_t); extern int socket(int,int,int); extern int setsockopt(int,int,int,char *,int); extern int getsockname(int,struct sockaddr *,int *); extern int bind(int,struct sockaddr *,int); extern int recvfrom(int,char *,int,int,struct sockaddr *,int *); extern int select(int,fd_set *,fd_set *,fd_set *,struct timeval *); extern void bzero(char *,int); extern int on_exit(void (*procp)(),caddr_t); extern int sendmsg(int,struct msghdr *,int); extern int getrlimit(int,struct rlimit *); extern int setrlimit(int,struct rlimit *); #endif /* SunOS */ /* * This module exports an interface for performing network I/O of * datagrams over different protocols. All system specific * implementations of this functionality are opaque to the layers * above this module. This module could be further divided into * generic IP protocol support and the actual system dependent * network I/O functionaliy. There does not seem to be any * benefit at this point since IP is the only network protocol * defined for RSVP. */ #ifdef __FreeBSD__ #define msg_accrights msg_control #define msg_accrightslen msg_controllen #endif /* __FreeBSD__ */ typedef int (*callback)(int); static fd_set rset,fset; static int rawmode = TRUE; static int closed = TRUE; static int ipproto_rsvp = IPPROTO_RSVP; static net_if unknown; static int ulist[NET_ADDR_SIZE]; static net_addr_type protocol_type[FD_SETSIZE]; static net_if interface[FD_SETSIZE]; static callback finalize[FD_SETSIZE]; static int failed(int fd); static void init(); static void final(); static void adjust(net_addr *addr,net_addr_type type); static int receive(int fd,net_addr *from,void *msg,int len,net_if *inf); static int add_interface(net_if *inf); static int del_interface(net_if *inf); static int fd_pu,fd_pup; static struct in_addr maddr; static int pid = SYS_ERROR; static int send_ipv4(net_addr_type type,struct sockaddr_in *to, struct sockaddr_in *from,void *msg,int len,net_if *inf, u_char hops,int ra); static int set_ancillary_data_ipv4(struct msghdr *hdr,net_addr_type type, struct sockaddr_in *to,struct sockaddr_in *from, void *msg,int len,net_if *inf,u_char hops,int ra); static int init_ancillary_data_ipv4(int fd); static int socket_ipv4(int type,int proto,net_addr_type atype); static int socket_recv_rsvp_ipv4(int proto); static int socket_recv_udp_ipv4(struct sockaddr_in *addr); static int join_multicast_ipv4(int fd,net_if *inf,struct in_addr *g); static int drop_multicast_ipv4(int fd,net_if *inf,struct in_addr *g); static int drop_all_multicast_ipv4(int fd); static int rsvp_on_ipv4(int fd); static int rsvp_off_ipv4(int fd); static int add_if_ipv4(net_if *inf,struct in_addr *g); static int del_if_ipv4(net_if *inf,struct in_addr *g); static int add_vif_ipv4(net_if *inf); static int del_vif_ipv4(net_if *inf); static int rsvp_vif_off_ipv4(int fd); #ifdef USE_IPV6 static int fd6_pu,fd6_pup; static struct in6_addr maddr6; static int send_ipv6(net_addr_type type,struct sockaddr_in6 *to, struct sockaddr_in6 *from,void *msg,int len,net_if *inf, u_char hops,int ra); static int set_ancillary_data_ipv6(struct msghdr *hdr,net_addr_type type, struct sockaddr_in6 *to,struct sockaddr_in6 *from, void *msg,int len,net_if *inf,u_char hops,int ra); static int init_ancillary_data_ipv6(int fd); static int socket_ipv6(int type,int proto,net_addr_type atype); static int socket_recv_rsvp_ipv6(int proto); static int socket_recv_udp_ipv6(struct sockaddr_in6 *addr); static int join_multicast_ipv6(int fd,net_if *inf,struct in6_addr *g); static int drop_multicast_ipv6(int fd,net_if *inf,struct in6_addr *g); static int drop_all_multicast_ipv6(int fd); static int rsvp_on_ipv6(int fd); static int rsvp_off_ipv6(int fd); static int add_if_ipv6(net_if *inf,struct in6_addr *g); static int del_if_ipv6(net_if *inf,struct in6_addr *g); static int add_vif_ipv6(net_if *inf); static int del_vif_ipv6(net_if *inf); static int initialize(int pu,int pup,struct in_addr *g,struct in6_addr *g6); #else /* USE_IPV6 */ static int initialize(int pu,int pup,struct in_addr *g); #endif /* USE_IPV6 */ /* * Initialize network I/O subsystem. */ int net_init_udp_only(net_addr *addr4) { int fd,size,status = SYS_NOERROR; net_addr *iaddr; struct sockaddr_in addr; #ifdef USE_IPV6 struct sockaddr_in6 addr6; #endif /* USE_IPV6 */ init(); rawmode = FALSE; /* Receive RSVP/UDP/IPv4 (Any Interface) */ iaddr = net_get_default_interface(); if ((iaddr != NULL) && (NET_GET_TYPE(iaddr) == NET_ADDR_IPv4)) { NET_SOCKADDR_IPv4(&addr,NET_GET_ADDR_IPv4(iaddr)); } else { NET_SOCKADDR_IPv4(&addr,inaddr_any); } fd = socket_recv_udp_ipv4(&addr); /* Send RSVP/UDP/IPv4 (Any Interface) */ ulist[NET_ADDR_UDP_IPv4] = fd; if (FAILED(fd)) status = SYS_ERROR; else { size = sizeof(addr); if (!FAILED(getsockname(fd,(struct sockaddr *) &addr,&size))) NET_SET_ADDR_UDP_IPv4(addr4,addr); } #ifdef USE_IPV6 /* Receive RSVP/UDP/IPv6 (Any Interface) */ NET_SOCKADDR_IPv6(&addr6,in6addr_any); fd = socket_recv_udp_ipv6(&addr6); /* Send RSVP/UDP/IPv6 (Any Interface) */ ulist[NET_ADDR_UDP_IPv6] = fd; if (FAILED(fd)) status = SYS_ERROR; #endif /* USE_IPV6 */ return(status); } int #ifdef USE_IPV6 net_init(int pu,int pup,struct in_addr *g,struct in6_addr *g6,int async) #else /* USE_IPV6 */ net_init(int pu,int pup,struct in_addr *g,int async) #endif /* USE_IPV6 */ { int fd,status = SYS_NOERROR; struct sockaddr_in addr; struct protoent *p; #ifdef USE_IPV6 struct sockaddr_in6 addr6; #endif /* USE_IPV6 */ init(); maddr = *g; p = getprotobyname("rsvp"); if (p != NULL) ipproto_rsvp = p->p_proto; if (async) { pid = getpid(); if (FAILED(pid)) return(SYS_ERROR); } /* Receive RSVP/IPv4 (Any Interface) */ fd = socket_recv_rsvp_ipv4(ipproto_rsvp); /* Send RSVP/IPv4 (Any Interface) */ ulist[NET_ADDR_IPv4] = fd; if (rawmode && FAILED(fd)) status = SYS_ERROR; /* Receive Multicast RSVP/UDP/IPv4 [Pu] (Any Interface) */ NET_SOCKADDR_UDP_IPv4(&addr,inaddr_any,pu); fd_pu = socket_recv_udp_ipv4(&addr); /* Send RSVP/UDP/IPv4 (Any Interface) */ ulist[NET_ADDR_UDP_IPv4] = fd_pu; if (FAILED(fd_pu)) status = SYS_ERROR; /* Receive Multicast RSVP/UDP/IPv4 [Pu'] (Any Interface) */ if (!rawmode) { NET_SOCKADDR_UDP_IPv4(&addr,inaddr_any,pup); fd_pup = socket_recv_udp_ipv4(&addr); if (FAILED(fd_pup)) status = SYS_ERROR; } #ifdef USE_IPV6 maddr6 = *g6; /* Receive RSVP/IPv6 (Any Interface) */ fd = socket_recv_rsvp_ipv6(ipproto_rsvp); /* Send RSVP/IPv6 (Any Interface) */ ulist[NET_ADDR_IPv6] = fd; if (rawmode && FAILED(fd)) status = SYS_ERROR; /* Receive Multicast RSVP/UDP/IPv6 [Pu] (Any Interface) */ NET_SOCKADDR_UDP_IPv6(&addr6,in6addr_any,pu); fd6_pu = socket_recv_udp_ipv6(&addr6); /* Send RSVP/UDP/IPv6 (Any Interface) */ ulist[NET_ADDR_UDP_IPv6] = fd6_pu; if (FAILED(fd6_pu)) status = SYS_ERROR; /* Receive Multicast RSVP/UDP/IPv6 [Pu'] (Any Interface) */ if (!rawmode) { NET_SOCKADDR_UDP_IPv6(&addr6,in6addr_any,pup); fd6_pup = socket_recv_udp_ipv6(&addr6); if (FAILED(fd6_pup)) status = SYS_ERROR; } if (FAILED(initialize(pu,pup,g,g6))) status = SYS_ERROR; #else /* USE_IPV6 */ if (FAILED(initialize(pu,pup,g))) status = SYS_ERROR; #endif /* USE_IPV6 */ return(status); } /* * Shutdown network I/O subsystem. */ int net_final() { int fd,status = SYS_NOERROR; if(closed) return(SYS_NOERROR); for (fd = 0;fd < FD_SETSIZE; fd++) if (FD_ISSET(fd,&fset)) { if (finalize[fd] != NULL) if(FAILED((*finalize[fd])(fd))) status = SYS_ERROR; FD_CLR(fd,&fset); if(FAILED(close(fd))) status = SYS_ERROR; } closed = TRUE; pid = SYS_ERROR; return(status); } int net_has_rawmode() { return(rawmode); } int net_poll_list(fd_set *set) { *set = rset; return(SYS_NOERROR); } /* * This is how the application tells us which multicast interfaces * to listen for UDP datagrams to G*. */ int net_add_interfaces(int n,net_if *list) { int i,status = SYS_NOERROR; for (i = 0;i < n; i++) if (FAILED(add_interface(&list[i]))) status = SYS_ERROR; return(status); } int net_del_interfaces(int n,net_if *list) { int i,status = SYS_NOERROR; for (i = 0;i < n; i++) if (FAILED(del_interface(&list[i]))) status = SYS_ERROR; return(status); } int net_recv(net_addr *from,void *msg,int len,net_if *inf) { int fd,n; fd_set lrset; struct timeval zero; timerclear(&zero); lrset = rset; n = select(FD_SETSIZE,&lrset,(fd_set *) NULL,(fd_set *) NULL,&zero); if (n < 1) return(n); for (fd = 0;fd < FD_SETSIZE; fd++) if (FD_ISSET(fd,&lrset)) return(receive(fd,from,msg,len,inf)); return(0); } /* * Send datagram using the appropriate transport protocol, which * is inferred from the address type. Flags interpretation are * protocol specific. Parameters "from" and "inf" can be * optionally set to NULL. */ int net_send(net_addr *to,net_addr *from,void *msg,int len, net_if *inf,u_char hops,int ra) { net_addr_type type; struct sockaddr_in st,sf,*fp = NULL; #ifdef USE_IPV6 struct sockaddr_in6 st6,sf6,*fp6 = NULL; #endif /* USE_IPV6 */ if ((from != NULL) && NET_UNEQUAL_TYPE(to,from)) return(SYS_ERROR); type = NET_GET_TYPE(to); switch (type) { case NET_ADDR_IPv4: NET_SOCKADDR_IPv4(&st,NET_GET_ADDR_IPv4(to)); if (from != NULL) { NET_SOCKADDR_IPv4(&sf, NET_GET_ADDR_IPv4(from)); fp = &sf; } return(send_ipv4(type,&st,fp,msg,len,inf,hops,ra)); case NET_ADDR_UDP_IPv4: st = NET_GET_ADDR_UDP_IPv4(to); if (from != NULL) fp = &NET_GET_ADDR_UDP_IPv4(from); return(send_ipv4(type,&st,fp,msg,len,inf,hops,ra)); #ifdef USE_IPV6 case NET_ADDR_IPv6: NET_SOCKADDR_IPv6(&st6,NET_GET_ADDR_IPv6(to)); if (from != NULL) { NET_SOCKADDR_IPv6(&sf6, NET_GET_ADDR_IPv6(from)); fp6 = &sf6; } return(send_ipv6(type,&st6,fp6,msg,len,inf,hops,ra)); case NET_ADDR_UDP_IPv6: st6 = NET_GET_ADDR_UDP_IPv6(to); if (from != NULL) fp6 = &NET_GET_ADDR_UDP_IPv6(from); return(send_ipv6(type,&st6,fp6,msg,len,inf,hops,ra)); #endif /* USE_IPV6 */ default: return(SYS_ERROR); } } static int failed(int fd) { FD_CLR(fd,&fset); close(fd); return(SYS_ERROR); } static void init() { static struct rlimit limits; static int noexit = TRUE; if (noexit) { #ifdef SunOS on_exit(final,0); #else /* SunOS */ atexit(final); #endif /* SunOS */ noexit = FALSE; } if (FAILED(getrlimit(RLIMIT_NOFILE,&limits))) net_error(NET_ERROR_SYSTEM,"getrlimit"); else { limits.rlim_cur = limits.rlim_max; if (FAILED(setrlimit(RLIMIT_NOFILE,&limits))) net_error(NET_ERROR_SYSTEM,"setrlimit"); } FD_ZERO(&rset); FD_ZERO(&fset); NET_SET_TYPE(&unknown,NET_IF_UNKNOWN); closed = FALSE; } static void final() { net_final(); } static void adjust(net_addr *addr,net_addr_type type) { NET_SET_TYPE(addr,type); switch(type) { case NET_ADDR_IPv4: NET_SET_ADDR_IPv4(addr, NET_GET_ADDR_UDP_IPv4(addr).sin_addr); break; #ifdef USE_IPV6 case NET_ADDR_IPv6: NET_SET_ADDR_IPv6(addr, NET_GET_ADDR_UDP_IPv6(addr).sin6_addr); break; #endif /* USE_IPV6 */ default: break; } } static int add_interface(net_if *inf) { switch(NET_GET_TYPE(inf)) { case NET_IF_PHY: switch (NET_GET_TYPE(&NET_GET_IF_PHY_ADDR(inf))) { case NET_ADDR_IPv4: return(add_if_ipv4(inf,&maddr)); #ifdef USE_IPV6 case NET_ADDR_IPv6: return(add_if_ipv6(inf,&maddr6)); #endif /* USE_IPV6 */ default: return(SYS_ERROR); } case NET_IF_VIF: switch (NET_GET_TYPE(&NET_GET_IF_VIF_ADDR(inf))) { case NET_ADDR_IPv4: return(add_vif_ipv4(inf)); #ifdef USE_IPV6 case NET_ADDR_IPv6: return(add_vif_ipv6(inf)); #endif /* USE_IPV6 */ default: return(SYS_ERROR); } default: return(SYS_ERROR); } } static int del_interface(net_if *inf) { switch(NET_GET_TYPE(inf)) { case NET_IF_PHY: switch (NET_GET_TYPE(&NET_GET_IF_PHY_ADDR(inf))) { case NET_ADDR_IPv4: return(del_if_ipv4(inf,&maddr)); #ifdef USE_IPV6 case NET_ADDR_IPv6: return(del_if_ipv6(inf,&maddr6)); #endif /* USE_IPV6 */ default: return(SYS_ERROR); } case NET_IF_VIF: switch (NET_GET_TYPE(&NET_GET_IF_VIF_ADDR(inf))) { case NET_ADDR_IPv4: return(del_vif_ipv4(inf)); #ifdef USE_IPV6 case NET_ADDR_IPv6: return(del_vif_ipv6(inf)); #endif /* USE_IPV6 */ default: return(SYS_ERROR); } default: return(SYS_ERROR); } } static int send_ipv4(net_addr_type type,struct sockaddr_in *to,struct sockaddr_in *from, void *msg,int len,net_if *inf,u_char hops,int ra) { int fd,n; struct msghdr hdr; hdr.msg_name = (void *) to; hdr.msg_namelen = sizeof(*to); hdr.msg_accrights = NULL; hdr.msg_accrightslen = 0; fd = set_ancillary_data_ipv4(&hdr,type,to,from,msg,len,inf,hops,ra); if (FAILED(fd)) return(fd); n = sendmsg(fd,&hdr,0); if (FAILED(n)) { net_error(NET_ERROR_SYSTEM,"sendmsg"); return(SYS_ERROR); } return(n); } static int socket_ipv4(int type,int proto,net_addr_type atype) { int fd,one = 1; u_char on = FALSE; fd = socket(AF_INET,type,proto); if (FAILED(fd)) { if (type == SOCK_RAW) { if (rawmode) { net_error(NET_ERROR_USER, "Using UDP encapsulation\n"); rawmode = FALSE; } } else net_error(NET_ERROR_SYSTEM,"socket"); return(fd); } if (FAILED(setsockopt(fd,SOL_SOCKET,SO_REUSEXXXX, (char *) &one,sizeof(one)))) { net_error(NET_ERROR_SYSTEM,"SO_REUSEXXXX"); return(failed(fd)); } if (!FAILED(pid)) { if (FAILED(fcntl(fd, F_SETFL, (fcntl(fd, F_GETFL) | FASYNC)))) return(failed(fd)); #ifndef SOLARIS if (FAILED(fcntl(fd, F_SETOWN, pid))) return(failed(fd)); #endif /* SOLARIS */ } /* Ignore errors on non-multicast interfaces */ setsockopt(fd,IPPROTO_IP,IP_MULTICAST_LOOP,(char *) &on,sizeof(on)); if (FAILED(init_ancillary_data_ipv4(fd))) return(failed(fd)); FD_SET(fd,&fset); protocol_type[fd] = atype; finalize[fd] = NULL; return(fd); } static int socket_recv_rsvp_ipv4(int proto) { int fd; fd = socket_ipv4(SOCK_RAW,proto,NET_ADDR_IPv4); if (FAILED(fd)) return(fd); if (FAILED(rsvp_on_ipv4(fd))) { net_error(NET_ERROR_USER,"Pre-3.3 multicast kernel\n"); return(failed(fd)); } FD_SET(fd,&rset); finalize[fd] = rsvp_off_ipv4; return(fd); } static int rsvp_on_ipv4(int fd) { #ifdef IP_RSVP_ON if (FAILED(setsockopt(fd,IPPROTO_IP,IP_RSVP_ON,(char *) NULL,0))) { net_error(NET_ERROR_SYSTEM,"IP_RSVP_ON"); return(SYS_ERROR); } #endif /* IP_RSVP_ON */ return(SYS_NOERROR); } static int rsvp_off_ipv4(int fd) { #ifdef IP_RSVP_OFF if (FAILED(setsockopt(fd,IPPROTO_IP,IP_RSVP_OFF,(char *) NULL,0))) { net_error(NET_ERROR_SYSTEM,"IP_RSVP_OFF"); return(SYS_ERROR); } #endif /* IP_RSVP_OFF */ return(SYS_NOERROR); } static int socket_recv_udp_ipv4(struct sockaddr_in *addr) { int fd; fd = socket_ipv4(SOCK_DGRAM,PF_UNSPEC,NET_ADDR_UDP_IPv4); if (FAILED(fd)) return(fd); if (FAILED(bind(fd,(struct sockaddr *) addr,sizeof(*addr)))) { net_error(NET_ERROR_SYSTEM,"bind"); return(failed(fd)); } FD_SET(fd,&rset); return(fd); } static int join_multicast_ipv4(int fd,net_if *inf,struct in_addr *g) { struct ip_mreq mreq; mreq.imr_multiaddr = *g; mreq.imr_interface = NET_GET_ADDR_IPv4(&NET_GET_IF_PHY_ADDR(inf)); /* Ignore errors on non-multicast interfaces */ if (FAILED(setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP, (char *) &mreq,sizeof(mreq)))) return(SYS_NOERROR); finalize[fd] = drop_all_multicast_ipv4; return(SYS_NOERROR); } static int drop_multicast_ipv4(int fd,net_if *inf,struct in_addr *g) { struct ip_mreq mreq; mreq.imr_multiaddr = *g; mreq.imr_interface = NET_GET_ADDR_IPv4(&NET_GET_IF_PHY_ADDR(inf)); if (FAILED(setsockopt(fd,IPPROTO_IP,IP_DROP_MEMBERSHIP, (char *) &mreq,sizeof(mreq)))) { net_error(NET_ERROR_SYSTEM,"IP_DROP_MEMBERSHIP"); return(SYS_ERROR); } return(SYS_NOERROR); } static int drop_all_multicast_ipv4(int fd) { /* FIX: Finish */ return(SYS_ERROR); } #ifdef USE_IPV6 static int send_ipv6(net_addr_type type,struct sockaddr_in6 *to,struct sockaddr_in6 *from, void *msg,int len,net_if *inf,u_char hops,int ra) { int fd,n; struct msghdr hdr; hdr.msg_name = (void *) to; hdr.msg_namelen = sizeof(*to); hdr.msg_accrights = NULL; hdr.msg_accrightslen = 0; fd = set_ancillary_data_ipv6(&hdr,type,to,from,msg,len,inf,hops,ra); if (FAILED(fd)) return(fd); n = sendmsg(fd,&hdr,0); if (FAILED(n)) { net_error(NET_ERROR_SYSTEM,"sendmsg-1"); return(SYS_ERROR); } return(n); } static int socket_ipv6(int type,int proto,net_addr_type atype) { int fd,one = 1; u_char on = FALSE; fd = socket(AF_INET6,type,proto); if (FAILED(fd)) { if (type == SOCK_RAW) { if (rawmode) { net_error(NET_ERROR_USER, "Using UDP encapsulation\n"); rawmode = FALSE; } } else net_error(NET_ERROR_SYSTEM,"socket"); return(fd); } if (FAILED(setsockopt(fd,SOL_SOCKET,SO_REUSEXXXX, (char *) &one,sizeof(one)))) { net_error(NET_ERROR_SYSTEM,"SO_REUSEXXXX"); return(failed(fd)); } if (!FAILED(pid)) { if (FAILED(fcntl(fd, F_SETFL, (fcntl(fd, F_GETFL) | FASYNC)))) return(failed(fd)); #ifndef SOLARIS if (FAILED(fcntl(fd, F_SETOWN, pid))) return(failed(fd)); #endif /* SOLARIS */ } /* Ignore errors on non-multicast interfaces */ setsockopt(fd,IPPROTO_IPV6,IPV6_MULTICAST_LOOP, (char *) &on,sizeof(on)); if (FAILED(init_ancillary_data_ipv6(fd))) return(failed(fd)); FD_SET(fd,&fset); protocol_type[fd] = atype; finalize[fd] = NULL; return(fd); } static int socket_recv_rsvp_ipv6(int proto) { int fd; fd = socket_ipv6(SOCK_RAW,proto,NET_ADDR_IPv6); if (FAILED(fd)) return(fd); if (FAILED(rsvp_on_ipv6(fd))) { net_error(NET_ERROR_USER,"Pre-3.3 multicast kernel\n"); return(failed(fd)); } FD_SET(fd,&rset); finalize[fd] = rsvp_off_ipv6; return(fd); } static int rsvp_on_ipv6(int fd) { #ifdef IPV6_RSVP_ON if (FAILED(setsockopt(fd,IPPROTO_IPV6,IPV6_RSVP_ON,(char *) NULL,0))) { net_error(NET_ERROR_SYSTEM,"IPV6_RSVP_ON"); return(SYS_ERROR); } #endif /* IPV6_RSVP_ON */ return(SYS_NOERROR); } static int rsvp_off_ipv6(int fd) { #ifdef IPV6_RSVP_OFF if (FAILED(setsockopt(fd,IPPROTO_IPV6,IPV6_RSVP_OFF,(char *) NULL,0))) { net_error(NET_ERROR_SYSTEM,"IPV6_RSVP_OFF"); return(SYS_ERROR); } #endif /* IPV6_RSVP_OFF */ return(SYS_NOERROR); } static int socket_recv_udp_ipv6(struct sockaddr_in6 *addr) { int fd; fd = socket_ipv6(SOCK_DGRAM,PF_UNSPEC,NET_ADDR_UDP_IPv6); if (FAILED(fd)) return(fd); if (FAILED(bind(fd,(struct sockaddr *) addr,sizeof(*addr)))) { net_error(NET_ERROR_SYSTEM,"bind"); return(failed(fd)); } FD_SET(fd,&rset); return(fd); } static int join_multicast_ipv6(int fd,net_if *inf,struct in6_addr *g) { struct ipv6_mreq mreq; mreq.ipv6mr_multiaddr = *g; #ifdef WORKAROUNDS mreq.ipv6mr_interface = NET_GET_ADDR_IPv6(&NET_GET_IF_PHY_ADDR(inf)); #else /* WORKAROUNDS */ mreq.ipv6mr_interface = NET_GET_IF_PHY_ID(inf); #endif /* WORKAROUNDS */ /* Ignore errors on non-multicast interfaces */ setsockopt(fd,IPPROTO_IPV6,IPV6_ADD_MEMBERSHIP, (char *) &mreq,sizeof(mreq)); finalize[fd] = drop_all_multicast_ipv6; return(SYS_NOERROR); } static int drop_multicast_ipv6(int fd,net_if *inf,struct in6_addr *g) { struct ipv6_mreq mreq; mreq.ipv6mr_multiaddr = *g; #ifdef WORKAROUNDS mreq.ipv6mr_interface = NET_GET_ADDR_IPv6(&NET_GET_IF_PHY_ADDR(inf)); #else /* WORKAROUNDS */ mreq.ipv6mr_interface = NET_GET_IF_PHY_ID(inf); #endif /* WORKAROUNDS */ if (FAILED(setsockopt(fd,IPPROTO_IPV6,IPV6_DROP_MEMBERSHIP, (char *) &mreq,sizeof(mreq)))) { net_error(NET_ERROR_SYSTEM,"IPV6_DROP_MEMBERSHIP"); return(SYS_ERROR); } return(SYS_NOERROR); } static int drop_all_multicast_ipv6(int fd) { /* FIX: Finish */ return(SYS_ERROR); } #endif /* USE_IPV6 */ #if (defined(USE_ANCILLARY_DATA) || defined(IP_RECVIF)) #define MAX_SOCK_CTRL 50 /* * Use ancillary data to get incoming network interface. */ static int receive(int fd,net_addr *from,void *msg,int len,net_if *inf) { int n; struct iovec iov; struct msghdr hdr; struct cmsghdr *chdr; net_addr addr; struct sockaddr_dl *sdl; char buffer[MAX_SOCK_CTRL]; hdr.msg_name = (void *) &NET_GET_ADDR(from); hdr.msg_namelen = sizeof(NET_GET_ADDR(from)); hdr.msg_control = buffer; hdr.msg_controllen = sizeof(buffer); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; iov.iov_base = msg; iov.iov_len = len; n = recvmsg(fd,&hdr,0); if (FAILED(n)) return(n); adjust(from,protocol_type[fd]); if (NET_GET_TYPE(&interface[fd]) == NET_IF_VIF) { *inf = interface[fd]; return(n); } *inf = unknown; if (hdr.msg_controllen == 0) return(n); for (chdr = CMSG_FIRSTHDR(&hdr); chdr != NULL; chdr = CMSG_NXTHDR(&hdr,chdr)) { if (chdr->cmsg_len == 0) continue; switch (chdr->cmsg_level) { case IPPROTO_IP: if (chdr->cmsg_type != IP_RECVIF) break; sdl = (struct sockaddr_dl *) CMSG_DATA(chdr); if (sdl->sdl_index == 0) break; NET_SET_ADDR_IPv4(&addr, ((struct sockaddr_in *) if_indextoaddr(sdl->sdl_index, AF_INET))->sin_addr); NET_SET_IF_PHY(inf,addr,sdl->sdl_index); break; #ifdef USE_IPV6 case IPPROTO_IPV6: if (chdr->cmsg_type != IPV6_RECVIF) break; sdl = (struct sockaddr_dl *) CMSG_DATA(chdr); if (sdl->sdl_index == 0) break; NET_SET_ADDR_IPv6(&addr, ((struct sockaddr_in6 *) if_indextoaddr(sdl->sdl_index, AF_INET6))->sin6_addr); NET_SET_IF_PHY(inf,addr,sdl->sdl_index); break; #endif /* USE_IPV6 */ default: break; } } return(n); } /* * Use ancillary data to specific outgoing network interface, * source address, hop count, and router alert option. This * function returns the file descriptor to use for the send * operation. */ static int init_ancillary_data_ipv4(int fd) { int on = TRUE; if (FAILED(setsockopt(fd,IPPROTO_IP,IP_RECVIF, (char *) &on,sizeof(on)))) { net_error(NET_ERROR_SYSTEM,"IP_RECVIF"); return(SYS_ERROR); } return(SYS_NOERROR); } #ifdef USE_IPV6 #ifdef IPV6_RECVIF static int init_ancillary_data_ipv6(int fd) { int on = TRUE; if (FAILED(setsockopt(fd,IPPROTO_IPV6,IPV6_RECVIF, (char *) &on,sizeof(on)))) { net_error(NET_ERROR_SYSTEM,"IPV6_RECVIF"); return(SYS_ERROR); } return(SYS_NOERROR); } #endif /* IPV6_RECVIF */ #endif /* USE_IPV6 */ #endif /* (defined(USE_ANCILLARY_DATA) || defined(IP_RECVIF)) */ #ifdef USE_ANCILLARY_DATA static int set_ancillary_data_ipv4(struct msghdr *hdr,net_addr_type type, struct sockaddr_in *to,struct sockaddr_in *from, void *msg,int len,net_if *inf,u_char hops,int ra) { /* FIX: fill in hdr->msg_control */ return(ulist[type]); } static int add_if_ipv4(net_if *inf,struct in_addr *g) { int status = SYS_NOERROR; /* Receive Multicast RSVP/UDP/IPv4 (Specified Interface) */ if (FAILED(join_multicast_ipv4(fd_pu,inf,g))) status = SYS_ERROR; if (!rawmode) { if (FAILED(join_multicast_ipv4(fd_pup,inf,g))) status = SYS_ERROR; } return(status); } static int del_if_ipv4(net_if *inf,struct in_addr *g) { int status = SYS_NOERROR; /* Receive Multicast RSVP/UDP/IPv4 (Specified Interface) */ if (FAILED(drop_multicast_ipv4(fd_pu,inf,g))) status = SYS_ERROR; if (!rawmode) { if (FAILED(drop_multicast_ipv4(fd_pup,inf,g))) status = SYS_ERROR; } return(status); } static int add_vif_ipv4(net_if *inf) { /* FIX: Finish */ return(SYS_ERROR); } static int del_vif_ipv4(net_if *inf) { /* FIX: Finish */ return(SYS_ERROR); } /* * Perform initialization and shutdown. */ static int #ifdef USE_IPV6 initialize(int pu,int pup,struct in_addr *g,struct in6_addr *g6) #else /* USE_IPV6 */ initialize(int pu,int pup,struct in_addr *g) #endif /* USE_IPV6 */ { return(SYS_NOERROR); } #ifdef USE_IPV6 static int init_ancillary_data_ipv6(int fd) { /* FIX: setsockopt(s) for ancillary data (IPV6_PKTINFO) */ return(SYS_ERROR); } static int set_ancillary_data_ipv6(struct msghdr *hdr,net_addr_type type, struct sockaddr_in6 *to,struct sockaddr_in6 *from, void *msg,int len,net_if *inf,u_char hops,int ra) { /* FIX: fill in hdr->msg_control */ return(ulist[type]); } static int add_if_ipv6(net_if *inf,struct in6_addr *g) { int status = SYS_NOERROR; /* Receive Multicast RSVP/UDP/IPv6 (Specified Interface) */ if (FAILED(join_multicast_ipv6(fd6_pu,inf,g))) status = SYS_ERROR; if (!rawmode) { if (FAILED(join_multicast_ipv6(fd6_pup,inf,g))) status = SYS_ERROR; } return(status); } static int del_if_ipv6(net_if *inf,struct in6_addr *g) { int status = SYS_NOERROR; /* Receive Multicast RSVP/UDP/IPv6 (Specified Interface) */ if (FAILED(drop_multicast_ipv6(fd6_pu,inf,g))) status = SYS_ERROR; if (!rawmode) { if (FAILED(drop_multicast_ipv6(fd6_pup,inf,g))) status = SYS_ERROR; } return(status); } static int add_vif_ipv6(net_if *inf) { /* FIX: Finish */ return(SYS_ERROR); } static int del_vif_ipv6(net_if *inf) { /* FIX: Finish */ return(SYS_ERROR); } #endif /* USE_IPV6 */ #else /* USE_ANCILLARY_DATA */ /* * These routine get complex for systems which cannot accept * ancillary data to sendmsg() to control the interface or vif to * use during the sending of a datagram in addition to router * alert options and hop limits. */ static int nvifs = 0; static int port_pu,port_pup,pmax = 0; static int plist[NET_ADDR_SIZE][FD_SETSIZE]; static int vlist[NET_ADDR_SIZE]; static int ipproto_udp = IPPROTO_UDP; static int set_hop_limit(int fd,int proto,int opt,void *option,int size); static int set_router_alert(int fd,int proto,int opt,void *options,int size); static int set_interface_ipv4(net_addr_type type,net_if *inf); static int socket_send_udp_ipv4(int proto); #ifdef USE_IPV6 static int set_interface_ipv6(net_addr_type type,net_if *inf); static int socket_send_udp_ipv6(int proto); #endif /* USE_IPV6 */ #ifndef IP_RECVIF /* * This function receives the packets using recvfrom(). */ static int receive(int fd,net_addr *from,void *msg,int len,net_if *inf) { int n,sz; sz = sizeof(NET_GET_ADDR(from)); n = recvfrom(fd,msg,len,0, (struct sockaddr *) &NET_GET_ADDR(from),&sz); if (FAILED(n)) return(n); adjust(from,protocol_type[fd]); *inf = interface[fd]; return(n); } static int init_ancillary_data_ipv4(int fd) { return(SYS_NOERROR); } #ifdef USE_IPV6 static int init_ancillary_data_ipv6(int fd) { return(SYS_NOERROR); } #endif /* USE_IPV6 */ #endif /* IP_RECVIF */ /* * Specific outgoing network interface, source address, hop count, * and router alert option. This function returns the file * descriptor to use for the send operation. */ static int set_ancillary_data_ipv4(struct msghdr *hdr,net_addr_type type, struct sockaddr_in *to,struct sockaddr_in *from, void *msg,int len,net_if *inf,u_char hops,int ra) { int fd,opt,size; struct udphdr uh; static struct iovec iov[2]; struct sockaddr_in sin; static u_char ra_ipv4[4] = {148, 4, 0, 0}; if (inf != NULL) fd = set_interface_ipv4(type,inf); else fd = ulist[type]; if (FAILED(fd)) return(fd); if (to != NULL) { if (IN_IS_ADDR_MULTICAST(&to->sin_addr)) { opt = IP_MULTICAST_TTL; #ifdef SET_IP_TTL } else opt = IP_TTL; #endif /* SET_IP_TTL */ if (FAILED(set_hop_limit(fd,IPPROTO_IP,opt, &hops,sizeof(hops)))) return(SYS_ERROR); #ifndef SET_IP_TTL } #endif /* SET_IP_TTL */ } if (FAILED(set_router_alert(fd,IPPROTO_IP,IP_OPTIONS,ra_ipv4, (ra ? sizeof(ra_ipv4) : 0)))) return(SYS_ERROR); hdr->msg_iov = iov; if ((type == NET_ADDR_UDP_IPv4) && rawmode) { if (from != NULL) uh.uh_sport = from->sin_port; else { size = sizeof(sin); if (FAILED(getsockname(fd,(struct sockaddr *) &sin, &size))) uh.uh_sport = 0; else uh.uh_sport = sin.sin_port; } uh.uh_dport = to->sin_port; uh.uh_ulen = htons(len + sizeof(uh)); uh.uh_sum = htons(0); /* RSVP checksum is enough */ iov[0].iov_base = (void *) &uh; iov[0].iov_len = sizeof(uh); iov[1].iov_base = msg; iov[1].iov_len = len; hdr->msg_iovlen = 2; } else { iov[0].iov_base = msg; iov[0].iov_len = len; hdr->msg_iovlen = 1; } return(fd); } /* * We must create a RAW socket to send RSVP traffic on a per * phyical interface basis. This is due to the fact that the * socket can only be bound once and cannot to rebound to another * interface dynamically. This is also true for UDP/IP traffic. */ static int add_if_ipv4(net_if *inf,struct in_addr *g) { int fd,status = SYS_NOERROR; struct in_addr in; struct sockaddr_in sin; in = NET_GET_ADDR_IPv4(&NET_GET_IF_PHY_ADDR(inf)); NET_SOCKADDR_IPv4(&sin,in); /* Send RSVP/IPv4 (Specified Interface) */ fd = socket_ipv4(SOCK_RAW,ipproto_rsvp,NET_ADDR_IPv4); if (FAILED(fd)) { if (rawmode) status = SYS_ERROR; } else { interface[fd] = *inf; if (FAILED(bind(fd,(struct sockaddr *) &sin,sizeof(sin)))) { net_error(NET_ERROR_SYSTEM,"bind"); failed(fd); fd = SYS_ERROR; status = SYS_ERROR; } /* Ignore errors on non-multicast interfaces */ setsockopt(fd,IPPROTO_IP,IP_MULTICAST_IF, (char *) &in,sizeof(in)); } plist[NET_ADDR_IPv4][pmax] = fd; /* Receive Multicast RSVP/UDP/IPv4 (Specified Interface) */ if (FAILED(join_multicast_ipv4(fd_pu,inf,g))) status = SYS_ERROR; if (!rawmode) { if (FAILED(join_multicast_ipv4(fd_pup,inf,g))) status = SYS_ERROR; } /* Receive Unicast RSVP/UDP/IPv4 (Specified Interface) */ NET_SOCKADDR_UDP_IPv4(&sin,in,rawmode ? port_pu : port_pup); fd = socket_recv_udp_ipv4(&sin); if (FAILED(fd)) status = SYS_ERROR; else interface[fd] = *inf; if (rawmode) { /* Send RSVP/UDP/IPv4 (Specified Interface) */ fd = socket_send_udp_ipv4(ipproto_udp); if (FAILED(fd)) status = SYS_ERROR; else interface[fd] = *inf; } if (!FAILED(fd)) { /* Ignore errors on non-multicast interfaces */ setsockopt(fd,IPPROTO_IP,IP_MULTICAST_IF, (char *) &in,sizeof(in)); plist[NET_ADDR_UDP_IPv4][pmax++] = fd; } return(status); } static int del_if_ipv4(net_if *inf,struct in_addr *g) { /* FIX: Finish */ return(SYS_ERROR); } /* * We can create a RAW socket to listen for RSVP traffic on a per * vif basis. This will let us to determine on which vif a * datagram was received. */ static int add_vif_ipv4(net_if *inf) { int fd; #ifdef IP_RSVP_VIF_ON int vif; #endif /* IP_RSVP_VIF_ON */ if (!rawmode) return(SYS_NOERROR); if (nvifs++ == 0) rsvp_off_ipv4(ulist[NET_ADDR_IPv4]); /* Receive RSVP/IPv4 (Specified VIF) */ fd = socket_ipv4(SOCK_RAW,ipproto_rsvp,NET_ADDR_IPv4); if (FAILED(fd)) return(fd); #ifdef IP_RSVP_VIF_ON vif = NET_GET_IF_VIF_ID(inf); if (FAILED(setsockopt(fd,IPPROTO_IP,IP_RSVP_VIF_ON, (char *) &vif,sizeof(vif)))) { net_error(NET_ERROR_SYSTEM,"IP_RSVP_VIF_ON"); return(failed(fd)); } #endif /* IP_RSVP_VIF_ON */ FD_SET(fd,&rset); interface[fd] = *inf; finalize[fd] = rsvp_vif_off_ipv4; return(SYS_NOERROR); } static int del_vif_ipv4(net_if *inf) { if (!rawmode) return(SYS_NOERROR); if (--nvifs == 0) rsvp_on_ipv4(ulist[NET_ADDR_IPv4]); /* FIX: Finish */ return(SYS_ERROR); } static int rsvp_vif_off_ipv4(int fd) { #ifdef IP_RSVP_VIF_OFF int vif; vif = NET_GET_IF_VIF_ID(&interface[fd]); if (FAILED(setsockopt(fd,IPPROTO_IP,IP_RSVP_VIF_OFF, (char *) &vif,sizeof(vif)))) { net_error(NET_ERROR_SYSTEM,"IP_RSVP_VIF_OFF"); return(SYS_ERROR); } #endif /* IP_RSVP_VIF_OFF */ return(SYS_NOERROR); } static int set_interface_ipv4(net_addr_type type,net_if *inf) { int i,fd,infn; net_addr *addr; struct in_addr in; switch(NET_GET_TYPE(inf)) { case NET_IF_PHY: if (NET_GET_TYPE(&NET_GET_IF_PHY_ADDR(inf)) != NET_ADDR_IPv4) return(SYS_ERROR); for (i = 0;i < pmax; i++) { fd = plist[type][i]; if (FAILED(fd)) continue; if (net_if_equal(inf,&interface[fd])) return(fd); } return(SYS_ERROR); case NET_IF_VIF: addr = &NET_GET_IF_VIF_ADDR(inf); if (NET_GET_TYPE(addr) != NET_ADDR_IPv4) return(SYS_ERROR); in = NET_GET_ADDR_IPv4(addr); fd = vlist[type]; if (FAILED(setsockopt(fd,IPPROTO_IP,IP_MULTICAST_IF, (char *) &in,sizeof(in)))) { net_error(NET_ERROR_SYSTEM,"IP_MULTICAST_IF"); return(SYS_ERROR); } #ifdef SOLARIS infn = 1; if (FAILED(setsockopt(fd,SOL_SOCKET,SO_DONTROUTE, (char *) &infn,sizeof(infn)))) { net_error(NET_ERROR_SYSTEM,"SO_DONTROUTE"); return(failed(fd)); } #else /* SOLARIS */ infn = NET_GET_IF_VIF_ID(inf); if (FAILED(setsockopt(fd,IPPROTO_IP,IP_MULTICAST_VIF, (char *) &infn,sizeof(infn)))) { net_error(NET_ERROR_SYSTEM,"IP_MULTICAST_VIF"); return(SYS_ERROR); } #endif /* SOLARIS */ return(fd); default: return(SYS_ERROR); } } static int socket_send_udp_ipv4(int proto) { if (rawmode) return(socket_ipv4(SOCK_RAW,proto,NET_ADDR_UDP_IPv4)); return(socket_ipv4(SOCK_DGRAM,PF_UNSPEC,NET_ADDR_UDP_IPv4)); } /* * Sending datagrams on physical interfaces and virtual interfaces * is handled by differing interfaces. Create a socket for * sending on any virtual interface. Sockets for sending on a * physical interface will be done on a per interface basis * below. */ static int #ifdef USE_IPV6 initialize(int pu,int pup,struct in_addr *g,struct in6_addr *g6) #else /* USE_IPV6 */ initialize(int pu,int pup,struct in_addr *g) #endif /* USE_IPV6 */ { int fd,status = SYS_NOERROR; struct protoent *p; p = getprotobyname("udp"); if (p != NULL) ipproto_udp = p->p_proto; port_pu = pu; port_pup = pup; for (fd = 0;fd < FD_SETSIZE; fd++) interface[fd] = unknown; /* Send RSVP/UDP/IPv4 (Any Interface) */ if (rawmode) { fd = socket_send_udp_ipv4(ipproto_udp); if (FAILED(fd)) status = SYS_ERROR; ulist[NET_ADDR_UDP_IPv4] = fd; } /* Send RSVP/IPv4 (Specified VIF) */ fd = socket_ipv4(SOCK_RAW,ipproto_rsvp,NET_ADDR_IPv4); if (rawmode && FAILED(fd)) status = SYS_ERROR; vlist[NET_ADDR_IPv4] = fd; /* Send RSVP/UDP/IPv4 (Specified VIF) */ fd = socket_send_udp_ipv4(ipproto_udp); vlist[NET_ADDR_UDP_IPv4] = fd; if (FAILED(fd)) status = SYS_ERROR; #ifdef USE_IPV6 /* Send RSVP/UDP/IPv6 (Any Interface) */ if (rawmode) { fd = socket_send_udp_ipv6(ipproto_udp); if (FAILED(fd)) status = SYS_ERROR; ulist[NET_ADDR_UDP_IPv6] = fd; } /* Send RSVP/IPv6 (Specified VIF) */ fd = socket_ipv6(SOCK_RAW,ipproto_rsvp,NET_ADDR_IPv6); if (rawmode && FAILED(fd)) status = SYS_ERROR; vlist[NET_ADDR_IPv6] = fd; /* Send RSVP/UDP/IPv6 (Specified VIF) */ fd = socket_send_udp_ipv6(ipproto_udp); vlist[NET_ADDR_UDP_IPv6] = fd; if (FAILED(fd)) status = SYS_ERROR; #endif /* USE_IPV6 */ return(status); } /* * Set the maximum hop limit. Once set, it remains set until it * is turned off. */ static int set_hop_limit(int fd,int proto,int opt,void *option,int size) { if (FAILED(setsockopt(fd,proto,opt,option,size))) { net_error(NET_ERROR_SYSTEM,"hop count"); return(SYS_ERROR); } return(SYS_NOERROR); } /* * Set the Router Alert Option. Once set, it remains set until it * is turned off. */ static int set_router_alert(int fd,int proto,int opt,void *options,int size) { if (FAILED(setsockopt(fd,proto,opt,options,size))) { net_error(NET_ERROR_SYSTEM,"Router alert"); return(SYS_ERROR); } return(SYS_NOERROR); } #ifdef USE_IPV6 static int set_ancillary_data_ipv6(struct msghdr *hdr,net_addr_type type, struct sockaddr_in6 *to,struct sockaddr_in6 *from, void *msg,int len,net_if *inf,u_char hops,int ra) { int fd,ihops = hops; static struct iovec iov[2]; if (inf != NULL) fd = set_interface_ipv6(type,inf); else fd = ulist[type]; if (FAILED(fd)) return(fd); if (to != NULL) { if (FAILED(set_hop_limit(fd,IPPROTO_IPV6, (IN6_IS_ADDR_MULTICAST(&to->sin6_addr) ? IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS), &ihops,sizeof(ihops)))) { #ifndef WORKAROUNDS return(SYS_ERROR); #endif /* WORKAROUNDS */ } } /* FIX: v6 router alert */ hdr->msg_iov = iov; /* FIX: v6 udp header */ /* if ((type == NET_ADDR_UDP_IPv6) && rawmode) { return(SYS_ERROR); } else { */ iov[0].iov_base = msg; iov[0].iov_len = len; hdr->msg_iovlen = 1; /* } */ return(fd); } static int add_if_ipv6(net_if *inf,struct in6_addr *g) { int fd,status = SYS_NOERROR; unsigned int index; struct in6_addr in; struct sockaddr_in6 sin; in = NET_GET_ADDR_IPv6(&NET_GET_IF_PHY_ADDR(inf)); NET_SOCKADDR_IPv6(&sin,in); /* Send RSVP/IPv6 (Specified Interface) */ fd = socket_ipv6(SOCK_RAW,ipproto_rsvp,NET_ADDR_IPv6); if (FAILED(fd)) { if (rawmode) status = SYS_ERROR; } else { interface[fd] = *inf; if (FAILED(bind(fd,(struct sockaddr *) &sin,sizeof(sin)))) { #ifndef WORKAROUNDS net_error(NET_ERROR_SYSTEM,"bind"); failed(fd); fd = SYS_ERROR; status = SYS_ERROR; #endif /* WORKAROUNDS */ } index = NET_GET_IF_PHY_ID(inf); /* Ignore errors on non-multicast interfaces */ setsockopt(fd,IPPROTO_IPV6,IPV6_MULTICAST_IF, (char *) &index,sizeof(index)); } plist[NET_ADDR_IPv6][pmax] = fd; /* Receive Multicast RSVP/UDP/IPv6 (Specified Interface) */ if (FAILED(join_multicast_ipv6(fd6_pu,inf,g))) status = SYS_ERROR; if (!rawmode) { if (FAILED(join_multicast_ipv6(fd6_pup,inf,g))) status = SYS_ERROR; } /* Receive Unicast RSVP/UDP/IPv6 (Specified Interface) */ NET_SOCKADDR_UDP_IPv6(&sin,in,rawmode ? port_pu : port_pup); fd = socket_recv_udp_ipv6(&sin); if (FAILED(fd)) status = SYS_ERROR; else interface[fd] = *inf; /* if (rawmode) { */ /* Send RSVP/UDP/IPv6 (Specified Interface) */ /* fd = socket_send_udp_ipv6(ipproto_udp); if (FAILED(fd)) status = SYS_ERROR; else interface[fd] = *inf; } */ plist[NET_ADDR_UDP_IPv6][pmax++] = fd; index = NET_GET_IF_PHY_ID(inf); /* Ignore errors on non-multicast interfaces */ setsockopt(fd,IPPROTO_IPV6,IPV6_MULTICAST_IF, (char *) &index,sizeof(index)); return(status); } static int del_if_ipv6(net_if *inf,struct in6_addr *g) { /* FIX: Finish */ return(SYS_ERROR); } static int add_vif_ipv6(net_if *inf) { /* FIX: Finish */ return(SYS_ERROR); } static int del_vif_ipv6(net_if *inf) { /* FIX: Finish */ return(SYS_ERROR); } static int set_interface_ipv6(net_addr_type type,net_if *inf) { int i,fd; switch(NET_GET_TYPE(inf)) { case NET_IF_PHY: if (NET_GET_TYPE(&NET_GET_IF_PHY_ADDR(inf)) != NET_ADDR_IPv6) return(SYS_ERROR); for (i = 0;i < pmax; i++) { fd = plist[type][i]; if (FAILED(fd)) continue; if (net_if_equal(inf,&interface[fd])) return(fd); } return(SYS_ERROR); default: return(SYS_ERROR); } } static int socket_send_udp_ipv6(int proto) { /* FIX: v6 udp header */ /* if (rawmode) return(socket_ipv6(SOCK_RAW,proto,NET_ADDR_UDP_IPv6)); */ return(socket_ipv6(SOCK_DGRAM,PF_UNSPEC,NET_ADDR_UDP_IPv6)); } #endif /* USE_IPV6 */ #endif /* USE_ANCILLARY_DATA */