欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

in6_pcb.c

eCos操作系统源码
C
第 1 页 / 共 2 页
字号:
{	if (in6p && in6p->in6p_hops >= 0)		return(in6p->in6p_hops);	else if (ifp)		return(nd_ifinfo[ifp->if_index].chlim);	else		return(ip6_defhlim);}#endifvoidin6_pcbdisconnect(inp)	struct inpcb *inp;{	bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr));	inp->inp_fport = 0;	/* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */	inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;	in_pcbrehash(inp);	if (inp->inp_socket->so_state & SS_NOFDREF)		in6_pcbdetach(inp);}voidin6_pcbdetach(inp)	struct inpcb *inp;{	struct socket *so = inp->inp_socket;	struct inpcbinfo *ipi = inp->inp_pcbinfo;#ifdef IPSEC	if (inp->in6p_sp != NULL)		ipsec6_delete_pcbpolicy(inp);#endif /* IPSEC */	inp->inp_gencnt = ++ipi->ipi_gencnt;	in_pcbremlists(inp);	sotoinpcb(so) = 0;	sofree(so);	if (inp->in6p_inputopts) /* Free all received options. */ 		m_freem(inp->in6p_inputopts->head); /* this is safe */ 	ip6_freepcbopts(inp->in6p_outputopts); 	ip6_freemoptions(inp->in6p_moptions);	if (inp->in6p_route.ro_rt)		rtfree(inp->in6p_route.ro_rt);	/* Check and free IPv4 related resources in case of mapped addr */	if (inp->inp_options)		(void)m_free(inp->inp_options);	ip_freemoptions(inp->inp_moptions);	inp->inp_vflag = 0;	zfreei(ipi->ipi_zone, inp);}/* * The calling convention of in6_setsockaddr() and in6_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) */intin6_setsockaddr(so, nam)	struct socket *so;	struct sockaddr **nam;{	int s;	register struct inpcb *inp;	register struct sockaddr_in6 *sin6;	/*	 * Do the malloc first in case it blocks.	 */	MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);	bzero(sin6, sizeof *sin6);	sin6->sin6_family = AF_INET6;	sin6->sin6_len = sizeof(*sin6);	s = splnet();	inp = sotoinpcb(so);	if (!inp) {		splx(s);		free(sin6, M_SONAME);		return EINVAL;	}	sin6->sin6_port = inp->inp_lport;	sin6->sin6_addr = inp->in6p_laddr;	splx(s);#ifndef SCOPEDROUTING	in6_recoverscope(sin6, &inp->in6p_laddr, NULL);#endif	*nam = (struct sockaddr *)sin6;	return 0;}intin6_setpeeraddr(so, nam)	struct socket *so;	struct sockaddr **nam;{	int s;	struct inpcb *inp;	register struct sockaddr_in6 *sin6;	/*	 * Do the malloc first in case it blocks.	 */	MALLOC(sin6, struct sockaddr_in6 *, sizeof(*sin6), M_SONAME, M_WAITOK);	bzero((caddr_t)sin6, sizeof (*sin6));	sin6->sin6_family = AF_INET6;	sin6->sin6_len = sizeof(struct sockaddr_in6);	s = splnet();	inp = sotoinpcb(so);	if (!inp) {		splx(s);		free(sin6, M_SONAME);		return EINVAL;	}	sin6->sin6_port = inp->inp_fport;	sin6->sin6_addr = inp->in6p_faddr;	splx(s);#ifndef SCOPEDROUTING	in6_recoverscope(sin6, &inp->in6p_faddr, NULL);#endif	*nam = (struct sockaddr *)sin6;	return 0;}intin6_mapped_sockaddr(struct socket *so, struct sockaddr **nam){	struct	inpcb *inp = sotoinpcb(so);	int	error;	if (inp == NULL)		return EINVAL;	if (inp->inp_vflag & INP_IPV4) {		error = in_setsockaddr(so, nam);		if (error == 0)			in6_sin_2_v4mapsin6_in_sock(nam);	} else	/* scope issues will be handled in in6_setsockaddr(). */	error = in6_setsockaddr(so, nam);	return error;}intin6_mapped_peeraddr(struct socket *so, struct sockaddr **nam){	struct	inpcb *inp = sotoinpcb(so);	int	error;	if (inp == NULL)		return EINVAL;	if (inp->inp_vflag & INP_IPV4) {		error = in_setpeeraddr(so, nam);		if (error == 0)			in6_sin_2_v4mapsin6_in_sock(nam);	} else	/* scope issues will be handled in in6_setpeeraddr(). */	error = in6_setpeeraddr(so, nam);	return error;}/* * Pass some notification to all connections of a protocol * associated with address dst.  The local address and/or port numbers * may be specified to limit the search.  The "usual action" will be * taken, depending on the ctlinput cmd.  The caller must filter any * cmds that are uninteresting (e.g., no error in the map). * Call the protocol specific routine (if any) to report * any errors for each matching socket. * * Must be called at splnet. */voidin6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)	struct inpcbhead *head;	struct sockaddr *dst, *src;	u_int fport_arg, lport_arg;	int cmd;	void *cmdarg;	void (*notify) __P((struct inpcb *, int));{	struct inpcb *inp, *ninp;	struct sockaddr_in6 sa6_src, *sa6_dst;	u_short	fport = fport_arg, lport = lport_arg;	u_int32_t flowinfo;	int _errno, s;	if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)		return;	sa6_dst = (struct sockaddr_in6 *)dst;	if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))		return;	/*	 * note that src can be NULL when we get notify by local fragmentation.	 */	sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;	flowinfo = sa6_src.sin6_flowinfo;	/*	 * Redirects go to all references to the destination,	 * and use in6_rtchange to invalidate the route cache.	 * Dead host indications: also use in6_rtchange to invalidate	 * the cache, and deliver the error to all the sockets.	 * Otherwise, if we have knowledge of the local port and address,	 * deliver only to that socket.	 */	if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {		fport = 0;		lport = 0;		bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr));		if (cmd != PRC_HOSTDEAD)			notify = in6_rtchange;	}	_errno = inet6ctlerrmap[cmd];	s = splnet(); 	for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { 		ninp = LIST_NEXT(inp, inp_list); 		if ((inp->inp_vflag & INP_IPV6) == 0)			continue;		/*		 * If the error designates a new path MTU for a destination		 * and the application (associated with this socket) wanted to		 * know the value, notify. Note that we notify for all		 * disconnected sockets if the corresponding application		 * wanted. This is because some UDP applications keep sending		 * sockets disconnected.		 * XXX: should we avoid to notify the value to TCP sockets?		 */		if (cmd == PRC_MSGSIZE && (inp->inp_flags & IN6P_MTU) != 0 &&		    (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||		     IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr,					&sa6_dst->sin6_addr))) {			ip6_notify_pmtu(inp, (struct sockaddr_in6 *)dst,					(u_int32_t *)cmdarg);		}		/*		 * Detect if we should notify the error. If no source and		 * destination ports are specifed, but non-zero flowinfo and		 * local address match, notify the error. This is the case		 * when the error is delivered with an encrypted buffer		 * by ESP. Otherwise, just compare addresses and ports		 * as usual.		 */		if (lport == 0 && fport == 0 && flowinfo &&		    inp->inp_socket != NULL &&		    flowinfo == (inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) &&		    IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &sa6_src.sin6_addr))			goto do_notify;		else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr,					     &sa6_dst->sin6_addr) ||			 inp->inp_socket == 0 ||			 (lport && inp->inp_lport != lport) ||			 (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&			  !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,					      &sa6_src.sin6_addr)) ||			 (fport && inp->inp_fport != fport))			continue;	  do_notify:		if (notify)			(*notify)(inp, _errno);	}	splx(s);}/* * Lookup a PCB based on the local address and port. */struct inpcb *in6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)	struct inpcbinfo *pcbinfo;	struct in6_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) {			if ((inp->inp_vflag & INP_IPV6) == 0)				continue;			if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&			    IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&			    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;				if ((inp->inp_vflag & INP_IPV6) == 0)					continue;				if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))					wildcard++;				if (!IN6_IS_ADDR_UNSPECIFIED(					&inp->in6p_laddr)) {					if (IN6_IS_ADDR_UNSPECIFIED(laddr))						wildcard++;					else if (!IN6_ARE_ADDR_EQUAL(						&inp->in6p_laddr, laddr))						continue;				} else {					if (!IN6_IS_ADDR_UNSPECIFIED(laddr))						wildcard++;				}				if (wildcard < matchwild) {					match = inp;					matchwild = wildcard;					if (matchwild == 0) {						break;					}				}			}		}		return (match);	}}voidin6_pcbpurgeif0(head, ifp)	struct in6pcb *head;	struct ifnet *ifp;{	struct in6pcb *in6p;	struct ip6_moptions *im6o;	struct in6_multi_mship *imm, *nimm;	for (in6p = head; in6p != NULL; in6p = LIST_NEXT(in6p, inp_list)) {		im6o = in6p->in6p_moptions;		if ((in6p->inp_vflag & INP_IPV6) &&		    im6o) {			/*			 * Unselect the outgoing interface if it is being			 * detached.			 */			if (im6o->im6o_multicast_ifp == ifp)				im6o->im6o_multicast_ifp = NULL;			/*			 * Drop multicast group membership if we joined			 * through the interface being detached.			 * XXX controversial - is it really legal for kernel			 * to force this?			 */			for (imm = im6o->im6o_memberships.lh_first;			     imm != NULL; imm = nimm) {				nimm = imm->i6mm_chain.le_next;				if (imm->i6mm_maddr->in6m_ifp == ifp) {					LIST_REMOVE(imm, i6mm_chain);					in6_delmulti(imm->i6mm_maddr);					free(imm, M_IPMADDR);				}			}		}	}}/* * 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. */voidin6_losing(in6p)	struct inpcb *in6p;{	struct rtentry *rt;	struct rt_addrinfo info;	if ((rt = in6p->in6p_route.ro_rt) != NULL) {		bzero((caddr_t)&info, sizeof(info));		info.rti_info[RTAX_DST] =			(struct sockaddr *)&in6p->in6p_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);		in6p->in6p_route.ro_rt = NULL;		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. */voidin6_rtchange(inp, _errno)	struct inpcb *inp;	int _errno;{	if (inp->in6p_route.ro_rt) {		rtfree(inp->in6p_route.ro_rt);		inp->in6p_route.ro_rt = 0;		/*		 * A new route can be allocated the next time		 * output is attempted.		 */	}}/* * Lookup PCB in hash list. */struct inpcb *in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp)	struct inpcbinfo *pcbinfo;	struct in6_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;	int faith;#if defined(NFAITH) && NFAITH > 0	faith = faithprefix(laddr);#else	faith = 0;#endif	/*	 * First look for an exact match.	 */	head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3] /* XXX */,					      lport, fport,					      pcbinfo->hashmask)];	LIST_FOREACH(inp, head, inp_hash) {		if ((inp->inp_vflag & INP_IPV6) == 0)			continue;		if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) &&		    IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&		    inp->inp_fport == fport &&		    inp->inp_lport == lport) {			/*			 * Found.			 */			return (inp);		}	}	if (wildcard) {		struct inpcb *local_wild = NULL;		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0,						      pcbinfo->hashmask)];		LIST_FOREACH(inp, head, inp_hash) {			if ((inp->inp_vflag & INP_IPV6) == 0)				continue;			if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&			    inp->inp_lport == lport) {				if (faith && (inp->inp_flags & INP_FAITH) == 0)					continue;				if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,						       laddr))					return (inp);				else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))					local_wild = inp;			}		}		return (local_wild);	}	/*	 * Not found.	 */	return (NULL);}voidinit_sin6(struct sockaddr_in6 *sin6, struct mbuf *m){	struct ip6_hdr *ip;	ip = mtod(m, struct ip6_hdr *);	bzero(sin6, sizeof(*sin6));	sin6->sin6_len = sizeof(*sin6);	sin6->sin6_family = AF_INET6;	sin6->sin6_addr = ip->ip6_src;	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))		sin6->sin6_addr.s6_addr16[1] = 0;	sin6->sin6_scope_id =		(m->m_pkthdr.rcvif && IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))		? m->m_pkthdr.rcvif->if_index : 0;	return;}

⌨️ 快捷键说明

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