⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 in_pcb.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		in_pcbdetach(inp);#ifdef IPSEC	ipsec_pcbdisconn(inp->inp_sp);#endif}voidin_pcbdetach(inp)	struct inpcb *inp;{	struct socket *so = inp->inp_socket;	struct inpcbinfo *ipi = inp->inp_pcbinfo;	struct rtentry *rt  = inp->inp_route.ro_rt;#ifdef IPSEC	ipsec4_delete_pcbpolicy(inp);#endif /*IPSEC*/	inp->inp_gencnt = ++ipi->ipi_gencnt;	in_pcbremlists(inp);	so->so_pcb = 0;	sofree(so);	if (inp->inp_options)		(void)m_free(inp->inp_options);	if (rt) {		/* 		 * route deletion requires reference count to be <= zero 		 */		if ((rt->rt_flags & RTF_DELCLONE) &&		    (rt->rt_flags & RTF_WASCLONED) &&		    (rt->rt_refcnt <= 1)) {			rt->rt_refcnt--;			rt->rt_flags &= ~RTF_UP;			rtrequest(RTM_DELETE, rt_key(rt),				  rt->rt_gateway, rt_mask(rt),				  rt->rt_flags, (struct rtentry **)0);		}		else			rtfree(rt);	}	ip_freemoptions(inp->inp_moptions);	inp->inp_vflag = 0;	zfreei(ipi->ipi_zone, inp);}/* * The calling convention of in_setsockaddr() and in_setpeeraddr() was * modified to match the pru_sockaddr() and pru_peeraddr() entry points * in struct pr_usrreqs, so that protocols can just reference then directly * without the need for a wrapper function.  The socket must have a valid * (i.e., non-nil) PCB, but it should be impossible to get an invalid one * except through a kernel programming error, so it is acceptable to panic * (or in this case trap) if the PCB is invalid.  (Actually, we don't trap * because there actually /is/ a programming error somewhere... XXX) */intin_setsockaddr(so, nam)	struct socket *so;	struct sockaddr **nam;{	int s;	register struct inpcb *inp;	register struct sockaddr_in *sin;	/*	 * Do the malloc first in case it blocks.	 */	MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,		M_WAITOK | M_ZERO);	sin->sin_family = AF_INET;	sin->sin_len = sizeof(*sin);	s = splnet();	inp = sotoinpcb(so);	if (!inp) {		splx(s);		free(sin, M_SONAME);		return ECONNRESET;	}	sin->sin_port = inp->inp_lport;	sin->sin_addr = inp->inp_laddr;	splx(s);	*nam = (struct sockaddr *)sin;	return 0;}intin_setpeeraddr(so, nam)	struct socket *so;	struct sockaddr **nam;{	int s;	struct inpcb *inp;	register struct sockaddr_in *sin;	/*	 * Do the malloc first in case it blocks.	 */	MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,		M_WAITOK | M_ZERO);	sin->sin_family = AF_INET;	sin->sin_len = sizeof(*sin);	s = splnet();	inp = sotoinpcb(so);	if (!inp) {		splx(s);		free(sin, M_SONAME);		return ECONNRESET;	}	sin->sin_port = inp->inp_fport;	sin->sin_addr = inp->inp_faddr;	splx(s);	*nam = (struct sockaddr *)sin;	return 0;}voidin_pcbnotifyall(head, faddr, _errno, notify)	struct inpcbhead *head;	struct in_addr faddr;	void (*notify) __P((struct inpcb *, int));{	struct inpcb *inp, *ninp;	int s;	s = splnet();	for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {		ninp = LIST_NEXT(inp, inp_list);#ifdef INET6		if ((inp->inp_vflag & INP_IPV4) == 0)			continue;#endif		if (inp->inp_faddr.s_addr != faddr.s_addr ||		    inp->inp_socket == NULL)				continue;		(*notify)(inp, _errno);	}	splx(s);}voidin_pcbpurgeif0(head, ifp)	struct inpcb *head;	struct ifnet *ifp;{	struct inpcb *inp;	struct ip_moptions *imo;	int i, gap;	for (inp = head; inp != NULL; inp = LIST_NEXT(inp, inp_list)) {		imo = inp->inp_moptions;		if ((inp->inp_vflag & INP_IPV4) &&		    imo != NULL) {			/*			 * Unselect the outgoing interface if it is being			 * detached.			 */			if (imo->imo_multicast_ifp == ifp)				imo->imo_multicast_ifp = NULL;			/*			 * Drop multicast group membership if we joined			 * through the interface being detached.			 */			for (i = 0, gap = 0; i < imo->imo_num_memberships;			    i++) {				if (imo->imo_membership[i]->inm_ifp == ifp) {					in_delmulti(imo->imo_membership[i]);					gap++;				} else if (gap != 0)					imo->imo_membership[i - gap] =					    imo->imo_membership[i];			}			imo->imo_num_memberships -= gap;		}	}}/* * Check for alternatives when higher level complains * about service problems.  For now, invalidate cached * routing information.  If the route was created dynamically * (by a redirect), time to try a default gateway again. */voidin_losing(inp)	struct inpcb *inp;{	register struct rtentry *rt;	struct rt_addrinfo info;	if ((rt = inp->inp_route.ro_rt)) {		bzero((caddr_t)&info, sizeof(info));		info.rti_info[RTAX_DST] =			(struct sockaddr *)&inp->inp_route.ro_dst;		info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;		info.rti_info[RTAX_NETMASK] = rt_mask(rt);		rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);		if (rt->rt_flags & RTF_DYNAMIC)			(void) rtrequest(RTM_DELETE, rt_key(rt),				rt->rt_gateway, rt_mask(rt), rt->rt_flags,				(struct rtentry **)0);		inp->inp_route.ro_rt = 0;		rtfree(rt);		/*		 * A new route can be allocated		 * the next time output is attempted.		 */	}}/* * After a routing change, flush old routing * and allocate a (hopefully) better one. */voidin_rtchange(inp, _errno)	register struct inpcb *inp;	int _errno;{	if (inp->inp_route.ro_rt) {		rtfree(inp->inp_route.ro_rt);		inp->inp_route.ro_rt = 0;		/*		 * A new route can be allocated the next time		 * output is attempted.		 */	}}/* * Lookup a PCB based on the local address and port. */struct inpcb *in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)	struct inpcbinfo *pcbinfo;	struct in_addr laddr;	u_int lport_arg;	int wild_okay;{	register struct inpcb *inp;	int matchwild = 3, wildcard;	u_short lport = lport_arg;	if (!wild_okay) {		struct inpcbhead *head;		/*		 * Look for an unconnected (wildcard foreign addr) PCB that		 * matches the local address and port we're looking for.		 */		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];		LIST_FOREACH(inp, head, inp_hash) {#ifdef INET6			if ((inp->inp_vflag & INP_IPV4) == 0)				continue;#endif			if (inp->inp_faddr.s_addr == INADDR_ANY &&			    inp->inp_laddr.s_addr == laddr.s_addr &&			    inp->inp_lport == lport) {				/*				 * Found.				 */				return (inp);			}		}		/*		 * Not found.		 */		return (NULL);	} else {		struct inpcbporthead *porthash;		struct inpcbport *phd;		struct inpcb *match = NULL;		/*		 * Best fit PCB lookup.		 *		 * First see if this local port is in use by looking on the		 * port hash list.		 */		porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,		    pcbinfo->porthashmask)];		LIST_FOREACH(phd, porthash, phd_hash) {			if (phd->phd_port == lport)				break;		}		if (phd != NULL) {			/*			 * Port is in use by one or more PCBs. Look for best			 * fit.			 */			LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {				wildcard = 0;#ifdef INET6				if ((inp->inp_vflag & INP_IPV4) == 0)					continue;#endif				if (inp->inp_faddr.s_addr != INADDR_ANY)					wildcard++;				if (inp->inp_laddr.s_addr != INADDR_ANY) {					if (laddr.s_addr == INADDR_ANY)						wildcard++;					else if (inp->inp_laddr.s_addr != laddr.s_addr)						continue;				} else {					if (laddr.s_addr != INADDR_ANY)						wildcard++;				}				if (wildcard < matchwild) {					match = inp;					matchwild = wildcard;					if (matchwild == 0) {						break;					}				}			}		}		return (match);	}}/* * Lookup PCB in hash list. */struct inpcb *in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard,		  ifp)	struct inpcbinfo *pcbinfo;	struct in_addr faddr, laddr;	u_int fport_arg, lport_arg;	int wildcard;	struct ifnet *ifp;{	struct inpcbhead *head;	register struct inpcb *inp;	u_short fport = fport_arg, lport = lport_arg;	/*	 * First look for an exact match.	 */	head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];	LIST_FOREACH(inp, head, inp_hash) {#ifdef INET6		if ((inp->inp_vflag & INP_IPV4) == 0)			continue;#endif		if (inp->inp_faddr.s_addr == faddr.s_addr &&		    inp->inp_laddr.s_addr == laddr.s_addr &&		    inp->inp_fport == fport &&		    inp->inp_lport == lport) {			/*			 * Found.			 */			return (inp);		}	}	if (wildcard) {		struct inpcb *local_wild = NULL;#if defined(INET6)		struct inpcb *local_wild_mapped = NULL;#endif /* defined(INET6) */		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];		LIST_FOREACH(inp, head, inp_hash) {#ifdef INET6			if ((inp->inp_vflag & INP_IPV4) == 0)				continue;#endif			if (inp->inp_faddr.s_addr == INADDR_ANY &&			    inp->inp_lport == lport) {#if defined(NFAITH) && NFAITH > 0				if (ifp && ifp->if_type == IFT_FAITH &&				    (inp->inp_flags & INP_FAITH) == 0)					continue;#endif				if (inp->inp_laddr.s_addr == laddr.s_addr)					return (inp);				else if (inp->inp_laddr.s_addr == INADDR_ANY) {#if defined(INET6)					if (INP_CHECK_SOCKAF(inp->inp_socket,							     AF_INET6))						local_wild_mapped = inp;					else#endif /* defined(INET6) */					local_wild = inp;				}			}		}#if defined(INET6)		if (local_wild == NULL)			return (local_wild_mapped);#endif /* defined(INET6) */		return (local_wild);	}	/*	 * Not found.	 */	return (NULL);}/* * Insert PCB onto various hash lists. */intin_pcbinshash(inp)	struct inpcb *inp;{	struct inpcbhead *pcbhash;	struct inpcbporthead *pcbporthash;	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;	struct inpcbport *phd;	u_int32_t hashkey_faddr;#ifdef INET6	if (inp->inp_vflag & INP_IPV6)		hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;	else#endif /* INET6 */	hashkey_faddr = inp->inp_faddr.s_addr;	pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,		 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];	pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,	    pcbinfo->porthashmask)];	/*	 * Go through port list and look for a head for this lport.	 */	LIST_FOREACH(phd, pcbporthash, phd_hash) {		if (phd->phd_port == inp->inp_lport)			break;	}	/*	 * If none exists, malloc one and tack it on.	 */	if (phd == NULL) {		MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT);		if (phd == NULL) {			return (ENOBUFS); /* XXX */		}		phd->phd_port = inp->inp_lport;		LIST_INIT(&phd->phd_pcblist);		LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);	}	inp->inp_phd = phd;	LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);	LIST_INSERT_HEAD(pcbhash, inp, inp_hash);	return (0);}/* * Move PCB to the proper hash bucket when { faddr, fport } have  been * changed. NOTE: This does not handle the case of the lport changing (the * hashed port list would have to be updated as well), so the lport must * not change after in_pcbinshash() has been called. */voidin_pcbrehash(inp)	struct inpcb *inp;{	struct inpcbhead *head;	u_int32_t hashkey_faddr;#ifdef INET6	if (inp->inp_vflag & INP_IPV6)		hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;	else#endif /* INET6 */	hashkey_faddr = inp->inp_faddr.s_addr;	head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,		inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];	LIST_REMOVE(inp, inp_hash);	LIST_INSERT_HEAD(head, inp, inp_hash);}/* * Remove PCB from various lists. */voidin_pcbremlists(inp)	struct inpcb *inp;{	inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;	if (inp->inp_lport) {		struct inpcbport *phd = inp->inp_phd;		LIST_REMOVE(inp, inp_hash);		LIST_REMOVE(inp, inp_portlist);		if (LIST_FIRST(&phd->phd_pcblist) == NULL) {			LIST_REMOVE(phd, phd_hash);			free(phd, M_PCB);		}	}	LIST_REMOVE(inp, inp_list);	inp->inp_pcbinfo->ipi_count--;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -