📄 in_pcb.c
字号:
/* in_pcb.c - internet protocol control block routines *//* Copyright 1984 - 2001 Wind River Systems, Inc. */#include "copyright_wrs.h"/* * Copyright (c) 1982, 1986, 1991, 1993, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 *//*modification history--------------------01g,12oct01,rae merge from truestack ver 01k, base 01f (SPR #69867 etc.)01f,05oct97,vin changed ip_freemoptions for new multicasting changes.01e,01jul97,vin added rtMissMsgHook for scalability of routing sockets.01d,31mar97,vin integrated with FREEBSD 2.2.1 for hashlookups of pcbs01c,05feb97,rjc changed for tos routing.01b,05dec96,vin replaced malloc with MALLOC and free with FREE(),01a,03mar96,vin created from BSD4.4 stuff,integrated with 02k of in_pcb.c*//*DESCRIPTION*/#include "vxWorks.h"#include "net/systm.h"#include "errno.h"#include "net/mbuf.h"#include "sys/socket.h"#include "net/socketvar.h"#include "sys/ioctl.h"#include "net/if.h"#include "netinet/in.h"#include "netinet/in_systm.h"#include "net/route.h"#include "netinet/in_pcb.h"#include "netinet/in_var.h"#include "netinet/ip_var.h"#include "net/protosw.h"#include "routeEnhLib.h"#ifdef VIRTUAL_STACK#include "netinet/vsLib.h"#endif /* VIRTUAL_STACK */#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET#include "wvNetLib.h"#endif#endifstruct in_addr zeroin_addr;#ifdef VIRTUAL_STACK#define IN_IFADDR _in_ifaddr#else#define IN_IFADDR in_ifaddr#endif#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* Set common fields of event identifiers for this module. */LOCAL UCHAR wvNetModuleId = WV_NET_INPCB_MODULE; /* Value for in_pcb.c */LOCAL UCHAR wvNetLocalFilter = WV_NET_NONE; /* Available event filter */LOCAL ULONG wvNetEventId; /* Event identifier: see wvNetLib.h */#endif /* INCLUDE_WVNET */#endifintin_pcballoc(so, pcbinfo) struct socket *so; struct inpcbinfo *pcbinfo;{ register struct inpcb *inp; int s; MALLOC(inp, struct inpcb *, sizeof(*inp), MT_PCB, M_DONTWAIT); if (inp == NULL) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_EMERGENCY event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_EMERGENCY, 13, 1, WV_NETEVENT_PCBALLOC_NOBUFS, so->so_fd)#endif /* INCLUDE_WVNET */#endif return (ENOBUFS); } bzero((caddr_t)inp, sizeof(*inp)); inp->inp_pcbinfo = pcbinfo; inp->inp_socket = so; s = splnet(); LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); in_pcbinshash(inp); splx(s); so->so_pcb = (caddr_t)inp; return (0);}intin_pcbbind(inp, nam) register struct inpcb *inp; struct mbuf *nam;{ register struct socket *so = inp->inp_socket; unsigned short *lastport = &inp->inp_pcbinfo->lastport; struct sockaddr_in *sin; u_short lport = 0; int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_VERBOSE event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_VERBOSE, 23, 11, WV_NETEVENT_PCBBIND_START, so->so_fd)#endif /* INCLUDE_WVNET */#endif#ifdef VIRTUAL_STACK if (_in_ifaddr == 0)#else if (in_ifaddr == 0)#endif /* VIRTUAL_STACK */ {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_ERROR, 10, 2, WV_NETEVENT_PCBBIND_NOADDR, so->so_fd)#endif /* INCLUDE_WVNET */#endif return (EADDRNOTAVAIL); } if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_3 (NET_AUX_EVENT, WV_NET_ERROR, 11, 3, WV_NETEVENT_PCBBIND_BADSOCK, so->so_fd, inp->inp_laddr.s_addr, inp->inp_lport)#endif /* INCLUDE_WVNET */#endif return (EINVAL); } if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || (so->so_options & SO_ACCEPTCONN) == 0)) wild = INPLOOKUP_WILDCARD; if (nam) { sin = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof (*sin)) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_ERROR, 12, 4, WV_NETEVENT_PCBBIND_BADADDRLEN, so->so_fd, nam->m_len)#endif /* INCLUDE_WVNET */#endif return (EINVAL); }#ifdef notdef /* * We should check the family, but old programs * incorrectly fail to initialize it. */ if (sin->sin_family != AF_INET) return (EAFNOSUPPORT);#endif lport = sin->sin_port; if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { /* * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; * allow complete duplication of binding if * SO_REUSEPORT is set, or if SO_REUSEADDR is set * and a multicast address is bound on both * new and duplicated sockets. */ if (so->so_options & SO_REUSEADDR) reuseport = SO_REUSEADDR|SO_REUSEPORT; } else if (sin->sin_addr.s_addr != INADDR_ANY) { sin->sin_port = 0; /* yech... */ if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_ERROR, 13, 5, WV_NETEVENT_PCBBIND_BADADDR, so->so_fd, sin->sin_addr.s_addr)#endif /* INCLUDE_WVNET */#endif return (EADDRNOTAVAIL); } } if (lport) { struct inpcb *t; /* GROSS */#if 0 /* XXX took out because we are always in super user mode. */ if (ntohs(lport) < IPPORT_RESERVED && (error = suser(p->p_ucred, &p->p_acflag))) return (EACCES);#endif t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, sin->sin_addr, lport, wild); if (t && (reuseport & t->inp_socket->so_options) == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_ERROR, 14, 6, WV_NETEVENT_PCBBIND_BADPORT, so->so_fd, lport)#endif /* INCLUDE_WVNET */#endif return (EADDRINUSE); } } inp->inp_laddr = sin->sin_addr; } if (lport == 0) do { ++*lastport; if (*lastport < IPPORT_RESERVED || *lastport > IPPORT_USERRESERVED) *lastport = IPPORT_RESERVED; lport = htons(*lastport); } while (in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, inp->inp_laddr, lport, wild)); inp->inp_lport = lport; in_pcbrehash(inp); return (0);}/* * Transform old in_pcbconnect() into an inner subroutine for new * in_pcbconnect(): Do some validity-checking on the remote * address (in mbuf 'nam') and then determine local host address * (i.e., which interface) to use to access that remote host. * * This preserves definition of in_pcbconnect(), while supporting a * slightly different version for T/TCP. (This is more than * a bit of a kludge, but cleaning up the internal interfaces would * have forced minor changes in every protocol). */intin_pcbladdr(inp, nam, plocal_sin) register struct inpcb *inp; struct mbuf *nam; struct sockaddr_in **plocal_sin;{ struct in_ifaddr *ia; register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof (*sin)) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_ERROR, 15, 7, WV_NETEVENT_PCBLADDR_BADADDR, inp->inp_socket->so_fd, nam->m_len, sin->sin_family, sin->sin_port)#endif /* INCLUDE_WVNET */#endif return (EINVAL); } if (sin->sin_family != AF_INET) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_ERROR, 15, 7, WV_NETEVENT_PCBLADDR_BADADDR, inp->inp_socket->so_fd, nam->m_len, sin->sin_family, sin->sin_port)#endif /* INCLUDE_WVNET */#endif return (EAFNOSUPPORT); } if (sin->sin_port == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_ERROR, 15, 7, WV_NETEVENT_PCBLADDR_BADADDR, inp->inp_socket->so_fd, nam->m_len, sin->sin_family, sin->sin_port)#endif /* INCLUDE_WVNET */#endif return (EADDRNOTAVAIL); } if (IN_IFADDR) { /* * If the destination address is INADDR_ANY, * use the primary local address. * If the supplied address is INADDR_BROADCAST, * and the primary interface supports broadcast, * choose the broadcast address for that interface. */#define satosin(sa) ((struct sockaddr_in *)(sa))#define sintosa(sin) ((struct sockaddr *)(sin))#define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) if (sin->sin_addr.s_addr == INADDR_ANY) sin->sin_addr = IA_SIN(IN_IFADDR)->sin_addr; else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST) { for (ia = IN_IFADDR; ia; ia = ia->ia_next) { if (ia->ia_ifp->if_flags & IFF_BROADCAST) { sin->sin_addr = satosin(&IN_IFADDR->ia_next->ia_broadaddr)->sin_addr; break; } } } } if (inp->inp_laddr.s_addr == INADDR_ANY) { register struct route *ro; 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. */ ro = &inp->inp_route; if (ro->ro_rt && (satosin(&ro->ro_dst)->sin_addr.s_addr != sin->sin_addr.s_addr || inp->inp_socket->so_options & SO_DONTROUTE)) { RTFREE(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; } if ((inp->inp_socket->so_options & 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); ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sin->sin_addr; TOS_SET ((struct sockaddr_in *) &ro->ro_dst, inp->inp_ip.ip_tos); rtalloc(ro); } /* * 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_short 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; if (ia == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_ERROR, 15, 7, WV_NETEVENT_PCBLADDR_BADADDR, inp->inp_socket->so_fd, nam->m_len, sin->sin_family, sin->sin_port)#endif /* INCLUDE_WVNET */#endif return (EADDRNOTAVAIL); } } /* * 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(ntohl(sin->sin_addr.s_addr)) && inp->inp_moptions != NULL) { struct ip_moptions *imo; struct ifnet *ifp; imo = inp->inp_moptions; if (imo->imo_multicast_ifp != NULL) { ifp = imo->imo_multicast_ifp; for (ia = IN_IFADDR; ia; ia = ia->ia_next) if (ia->ia_ifp == ifp) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -