diff options
Diffstat (limited to 'sys/netinet/in_pcb.c')
-rw-r--r-- | sys/netinet/in_pcb.c | 146 |
1 files changed, 134 insertions, 12 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 91b157519d6..71458addf74 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.34 1999/05/16 21:48:29 niklas Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.35 1999/12/08 06:50:19 itojun Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -73,7 +73,7 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <dev/rndvar.h> #ifdef INET6 -#include <netinet6/ipv6_var.h> +#include <netinet6/ip6_var.h> #endif /* INET6 */ #ifdef IPSEC @@ -82,6 +82,12 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. extern int check_ipsec_policy __P((struct inpcb *, u_int32_t)); #endif +#if 0 /*KAME IPSEC*/ +#include <netinet6/ipsec.h> +#include <netkey/key.h> +#include <netkey/key_debug.h> +#endif /* IPSEC */ + struct in_addr zeroin_addr; extern int ipsec_auth_default_level; @@ -165,6 +171,7 @@ in_pcballoc(so, v) &inp->inp_laddr, inp->inp_lport), inp, inp_hash); splx(s); so->so_pcb = inp; + inp->inp_hops = -1; #ifdef INET6 /* @@ -355,10 +362,8 @@ in_pcbconnect(v, nam) struct mbuf *nam; { register struct inpcb *inp = v; - struct in_ifaddr *ia; struct sockaddr_in *ifaddr = NULL; register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); - struct sockaddr_in *sin2; #ifdef INET6 if (sotopf(inp->inp_socket) == PF_INET6) @@ -386,7 +391,10 @@ in_pcbconnect(v, nam) sin->sin_addr = in_ifaddr.tqh_first->ia_broadaddr.sin_addr; } if (inp->inp_laddr.s_addr == INADDR_ANY) { +#if 0 register struct route *ro; + struct sockaddr_in *sin2; + struct in_ifaddr *ia; ia = (struct in_ifaddr *)0; /* @@ -446,10 +454,11 @@ in_pcbconnect(v, nam) if (IN_MULTICAST(sin->sin_addr.s_addr) && #ifdef INET6 inp->inp_moptions != NULL && - !(inp->inp_flags & INP_IPV6_MCAST)) { + !(inp->inp_flags & INP_IPV6_MCAST)) #else - inp->inp_moptions != NULL) { + inp->inp_moptions != NULL) #endif + { struct ip_moptions *imo; struct ifnet *ifp; @@ -465,6 +474,16 @@ in_pcbconnect(v, nam) } } ifaddr = satosin(&ia->ia_addr); +#else + int error; + ifaddr = in_selectsrc(sin, &inp->inp_route, + inp->inp_socket->so_options, inp->inp_moptions, &error); + if (ifaddr == NULL) { + if (error == 0) + error = EADDRNOTAVAIL; + return error; + } +#endif } if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port, inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, @@ -515,6 +534,14 @@ in_pcbdetach(v) struct socket *so = inp->inp_socket; int s; +#if 0 /*KAME IPSEC*/ + if (so->so_pcb) { + KEYDEBUG(KEYDEBUG_KEY_STAMP, + printf("DP call free SO=%p from in_pcbdetach\n", so)); + key_freeso(so); + } + ipsec4_delete_pcbpolicy(inp); +#endif /*IPSEC*/ so->so_pcb = 0; sofree(so); if (inp->inp_options) @@ -522,10 +549,10 @@ in_pcbdetach(v) if (inp->inp_route.ro_rt) rtfree(inp->inp_route.ro_rt); #ifdef INET6 - if (inp->inp_flags & INP_IPV6_MCAST) - ipv6_freemoptions(inp->inp_moptions6); + if (inp->inp_flags & INP_IPV6) + ip6_freemoptions(inp->inp_moptions6); else -#endif /* INET6 */ +#endif ip_freemoptions(inp->inp_moptions); #ifdef IPSEC /* XXX IPsec cleanup here */ @@ -778,8 +805,9 @@ in_pcblookup(table, faddrp, fport_arg, laddrp, lport_arg, flags) if (!IN6_IS_ADDR_UNSPECIFIED(faddr6)) wildcard++; } - } else { + } else #endif /* INET6 */ + { if (inp->inp_faddr.s_addr != INADDR_ANY) { if (faddr.s_addr == INADDR_ANY) wildcard++; @@ -799,9 +827,7 @@ in_pcblookup(table, faddrp, fport_arg, laddrp, lport_arg, flags) if (laddr.s_addr != INADDR_ANY) wildcard++; } -#ifdef INET6 } -#endif /* INET6 */ if ((!wildcard || (flags & INPLOOKUP_WILDCARD)) && wildcard < matchwild) { match = inp; @@ -812,6 +838,100 @@ in_pcblookup(table, faddrp, fport_arg, laddrp, lport_arg, flags) return (match); } +struct sockaddr_in * +in_selectsrc(sin, ro, soopts, mopts, errorp) + struct sockaddr_in *sin; + struct route *ro; + int soopts; + struct ip_moptions *mopts; + int *errorp; +{ + struct sockaddr_in *sin2; + struct in_ifaddr *ia; + + ia = (struct in_ifaddr *)0; + /* + * If route is known or can be allocated now, + * our src addr is taken from the i/f, else punt. + */ + if (ro->ro_rt && + (satosin(&ro->ro_dst)->sin_addr.s_addr != + sin->sin_addr.s_addr || + soopts & SO_DONTROUTE)) { + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)0; + } + if ((soopts & SO_DONTROUTE) == 0 && /*XXX*/ + (ro->ro_rt == (struct rtentry *)0 || + ro->ro_rt->rt_ifp == (struct ifnet *)0)) { + /* No route yet, so try to acquire one */ + ro->ro_dst.sa_family = AF_INET; + ro->ro_dst.sa_len = sizeof(struct sockaddr_in); + satosin(&ro->ro_dst)->sin_addr = sin->sin_addr; + rtalloc(ro); + + /* + * It is important to bzero out the rest of the + * struct sockaddr_in when mixing v6 & v4! + */ + sin2 = (struct sockaddr_in *)&ro->ro_dst; + bzero(sin2->sin_zero, sizeof(sin2->sin_zero)); + } + /* + * If we found a route, use the address + * corresponding to the outgoing interface + * unless it is the loopback (in case a route + * to our address on another net goes to loopback). + */ + if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) + ia = ifatoia(ro->ro_rt->rt_ifa); + if (ia == 0) { + u_int16_t fport = sin->sin_port; + + sin->sin_port = 0; + ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); + if (ia == 0) + ia = ifatoia(ifa_ifwithnet(sintosa(sin))); + sin->sin_port = fport; + if (ia == 0) + ia = in_ifaddr.tqh_first; + if (ia == 0) { + *errorp = EADDRNOTAVAIL; + return NULL; + } + } + /* + * If the destination address is multicast and an outgoing + * interface has been set as a multicast option, use the + * address of that interface as our source address. + */ + if (IN_MULTICAST(sin->sin_addr.s_addr) && +#if 0 /*def INET6*/ + mopts != NULL && + !(inp->inp_flags & INP_IPV6_MCAST)) +#else + mopts != NULL) +#endif + { + struct ip_moptions *imo; + struct ifnet *ifp; + + imo = mopts; + if (imo->imo_multicast_ifp != NULL) { + ifp = imo->imo_multicast_ifp; + for (ia = in_ifaddr.tqh_first; ia != 0; + ia = ia->ia_list.tqe_next) + if (ia->ia_ifp == ifp) + break; + if (ia == 0) { + *errorp = EADDRNOTAVAIL; + return NULL; + } + } + } + return satosin(&ia->ia_addr); +} + void in_pcbrehash(inp) struct inpcb *inp; @@ -919,3 +1039,5 @@ in6_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg) return (inp); } #endif /* INET6 */ + + |