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

📄 udp_usrreq.c

📁 嵌入式操作系统ECOS的网络开发包
💻 C
📖 第 1 页 / 共 3 页
字号:
					    inp->inp_fport != uh->uh_sport)
			        continue;
			} else
#endif /* INET6 */
			if (inp->inp_faddr.s_addr != INADDR_ANY) {
				if (inp->inp_faddr.s_addr !=
				    ip->ip_src.s_addr ||
				    inp->inp_fport != uh->uh_sport)
					continue;
			}

			if (last != NULL) {
				struct mbuf *n;

				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
					opts = NULL;
#ifdef INET6
					if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS))
						ip6_savecontrol(inp, &opts, ipv6, n);
#endif /* INET6 */
					m_adj(n, iphlen);
					if (sbappendaddr(&last->so_rcv,
#ifdef INET6							 
					/*
					 * This cruft is needed in (the rare)
					 * case I deliver a {multi,broad}cast
					 * IPv4 packet to an AF_INET6 socket.
					 */
					    ((((struct inpcb *)last->so_pcb)->inp_flags
					    & INP_IPV6) && ip) ?
					    (struct sockaddr *)&src_v4mapped :
#endif /* INET6 */
					    &srcsa.sa, n, opts) == 0) {
						m_freem(n);
						udpstat.udps_fullsock++;
					} else
						sorwakeup(last);
				}
			}
			last = inp->inp_socket;
			/*
			 * Don't look for additional matches if this one does
			 * not have either the SO_REUSEPORT or SO_REUSEADDR
			 * socket options set.  This heuristic avoids searching
			 * through all pcbs in the common case of a non-shared
			 * port.  It * assumes that an application will never
			 * clear these options after setting them.
			 */
			if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
				break;
		}

		if (last == NULL) {
			/*
			 * No matching pcb found; discard datagram.
			 * (No need to send an ICMP Port Unreachable
			 * for a broadcast or multicast datgram.)
			 */
			udpstat.udps_noportbcast++;
			goto bad;
		}

		opts = NULL;
#ifdef INET6
		if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS))
			ip6_savecontrol(inp, &opts, ipv6, m);
#endif /* INET6 */
		m_adj(m, iphlen);
		if (sbappendaddr(&last->so_rcv, 
#ifdef INET6
	        /*
		 * This cruft is needed in (the rare) case I
		 * deliver a {multi,broad}cast IPv4 packet to
		 * an AF_INET6 socket.
		 */
		    ((((struct inpcb *)last->so_pcb)->inp_flags & INP_IPV6) && ip) ?
		    (struct sockaddr *)&src_v4mapped :
#endif /* INET6 */
		    &srcsa.sa, m, opts) == 0) {
			udpstat.udps_fullsock++;
			goto bad;
		}
		sorwakeup(last);
		return;
	}
	/*
	 * Locate pcb for datagram.
	 */
#ifdef INET6
	if (ipv6)
		inp = in6_pcbhashlookup(&udbtable, &ipv6->ip6_src, uh->uh_sport,
		    &ipv6->ip6_dst, uh->uh_dport);
	else
#endif /* INET6 */
	inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport,
	    ip->ip_dst, uh->uh_dport);
	if (inp == 0) {
		++udpstat.udps_pcbhashmiss;
#ifdef INET6
		if (ipv6) {
			inp = in_pcblookup(&udbtable,
			    (struct in_addr *)&(ipv6->ip6_src),
			    uh->uh_sport, (struct in_addr *)&(ipv6->ip6_dst),
			    uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
		} else
#endif /* INET6 */
		inp = in_pcblookup(&udbtable, &ip->ip_src, uh->uh_sport,
		    &ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
		if (inp == 0) {
			udpstat.udps_noport++;
			if (m->m_flags & (M_BCAST | M_MCAST)) {
				udpstat.udps_noportbcast++;
				goto bad;
			}
#ifdef INET6
			if (ipv6) {
				icmp6_error(m, ICMP6_DST_UNREACH,
				    ICMP6_DST_UNREACH_NOPORT,0);
			} else
#endif /* INET6 */
			{
				*ip = save_ip;
				HTONS(ip->ip_len);
				HTONS(ip->ip_id);
				HTONS(ip->ip_off);
				uh->uh_sum = savesum;
				icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT,
					0, 0);
			}
			return;
		}
	}

#ifdef IPSEC
	/* Check if this socket requires security for incoming packets */
	if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE &&
	     !(m->m_flags & M_AUTH)) ||
	    (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&
	     !(m->m_flags & M_CONF))) {
#ifdef notyet
#ifdef INET6
		if (ipv6)
			ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
		else
#endif /* INET6 */
		icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
		m = NULL;
#endif /* notyet */
		udpstat.udps_nosec++;
		goto bad;
	}
	/* Use tdb_bind_out for this inp's outbound communication */
	if (tdb)
		tdb_add_inp(tdb, inp);
#endif /*IPSEC */

	opts = NULL;
#ifdef INET6
	if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS))
		ip6_savecontrol(inp, &opts, ipv6, m);
#endif /* INET6 */
	if (ip && (inp->inp_flags & INP_CONTROLOPTS)) {
		struct mbuf **mp = &opts;

		if (inp->inp_flags & INP_RECVDSTADDR) {
			*mp = udp_saveopt((caddr_t) &ip->ip_dst,
			    sizeof(struct in_addr), IP_RECVDSTADDR);
			if (*mp)
				mp = &(*mp)->m_next;
		}
#ifdef notyet
		/* options were tossed above */
		if (inp->inp_flags & INP_RECVOPTS) {
			*mp = udp_saveopt((caddr_t) opts_deleted_above,
			    sizeof(struct in_addr), IP_RECVOPTS);
			if (*mp)
				mp = &(*mp)->m_next;
		}
		/* ip_srcroute doesn't do what we want here, need to fix */
		if (inp->inp_flags & INP_RECVRETOPTS) {
			*mp = udp_saveopt((caddr_t) ip_srcroute(),
			    sizeof(struct in_addr), IP_RECVRETOPTS);
			if (*mp)
				mp = &(*mp)->m_next;
		}
#endif
	}
	iphlen += sizeof(struct udphdr);
	m_adj(m, iphlen);
	if (sbappendaddr(&inp->inp_socket->so_rcv,
#ifdef INET6
	    /*
	     * This cruft is needed to deliver a IPv4 packet to
	     * an AF_INET6 socket.
	     */
	    ((((struct inpcb *)inp->inp_socket->so_pcb)->inp_flags & INP_IPV6)
	    && ip) ? (struct sockaddr *)&src_v4mapped : 
#endif /* INET6 */
		&srcsa.sa, m, opts) == 0) {
		udpstat.udps_fullsock++;
		goto bad;
	}
	sorwakeup(inp->inp_socket);
	return;
bad:
	m_freem(m);
	if (opts)
		m_freem(opts);
}

/*
 * Create a "control" mbuf containing the specified data
 * with the specified type for presentation with a datagram.
 */
struct mbuf *
udp_saveopt(p, size, type)
	caddr_t p;
	register int size;
	int type;
{
	register struct cmsghdr *cp;
	struct mbuf *m;

	if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
		return ((struct mbuf *) NULL);
	cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
	bcopy(p, CMSG_DATA(cp), size);
	size += sizeof(*cp);
	m->m_len = size;
	cp->cmsg_len = size;
	cp->cmsg_level = IPPROTO_IP;
	cp->cmsg_type = type;
	return (m);
}

/*
 * Notify a udp user of an asynchronous error;
 * just wake up so that he can collect error status.
 */
static void
udp_notify(inp, errno)
	register struct inpcb *inp;
	int errno;
{
	inp->inp_socket->so_error = errno;
	sorwakeup(inp->inp_socket);
	sowwakeup(inp->inp_socket);
}

#if defined(INET6) && !defined(TCP6)
void
udp6_ctlinput(cmd, sa, d)
	int cmd;
	struct sockaddr *sa;
	void *d;
{
	struct sockaddr_in6 sa6;
	struct ip6_hdr *ip6;
	struct mbuf *m;
	int off;

	if (sa == NULL)
		return;
	if (sa->sa_family != AF_INET6)
		return;

	/* decode parameter from icmp6. */
	if (d != NULL) {
		struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
		ip6 = ip6cp->ip6c_ip6;
		m = ip6cp->ip6c_m;
		off = ip6cp->ip6c_off;
	} else
		return;

	/* translate addresses into internal form */
	sa6 = *(struct sockaddr_in6 *)sa;
	if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
		sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
	sa = (struct sockaddr *)&sa6;

	(void)udp_ctlinput(cmd, sa, (void *)ip6);
}
#endif

void *
udp_ctlinput(cmd, sa, v)
	int cmd;
	struct sockaddr *sa;
	void *v;
{
	register struct ip *ip = v;
	register struct udphdr *uh;
	extern int inetctlerrmap[];
	void (*notify) __P((struct inpcb *, int)) = udp_notify;
	int errno;

	if ((unsigned)cmd >= PRC_NCMDS)
		return NULL;
	errno = inetctlerrmap[cmd];
	if (PRC_IS_REDIRECT(cmd))
		notify = in_rtchange, ip = 0;
	else if (cmd == PRC_HOSTDEAD)
		ip = 0;
	else if (errno == 0)
		return NULL;
	if (sa == NULL)
		return NULL;
#ifdef INET6
	if (sa->sa_family == AF_INET6) {
		if (ip) {
			struct ip6_hdr *ipv6 = (struct ip6_hdr *)ip;
		
			uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ip6_hdr));
#if 0 /*XXX*/
			in6_pcbnotify(&udbtable, sa, uh->uh_dport,
			    &(ipv6->ip6_src), uh->uh_sport, cmd, udp_notify);
#endif
		} else {
#if 0 /*XXX*/
			in6_pcbnotify(&udbtable, sa, 0,
			    (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify);
#endif
		}
	} else
#endif /* INET6 */
	if (ip) {
		uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
		in_pcbnotify(&udbtable, sa, uh->uh_dport, ip->ip_src,
		    uh->uh_sport, errno, notify);
	} else
		in_pcbnotifyall(&udbtable, sa, errno, notify);
	return NULL;
}

int
#if __STDC__
udp_output(struct mbuf *m, ...)
#else
udp_output(m, va_alist)
	struct mbuf *m;
	va_dcl
#endif
{
	register struct inpcb *inp;
	struct mbuf *addr, *control;
	register struct udpiphdr *ui;
	register int len = m->m_pkthdr.len;
	struct in_addr laddr;
	int s = 0, error = 0;
	va_list ap;
#ifdef INET6
	register struct in6_addr laddr6;
	int v6packet = 0;
	struct sockaddr_in6 *sin6 = NULL;
	struct ip6_pktopts opt, *stickyopt = NULL;
#endif /* INET6 */
	int pcbflags = 0;

	va_start(ap, m);
	inp = va_arg(ap, struct inpcb *);
	addr = va_arg(ap, struct mbuf *);
	control = va_arg(ap, struct mbuf *);
	va_end(ap);

#ifdef INET6
	v6packet = ((inp->inp_flags & INP_IPV6) &&
		    !(inp->inp_flags & INP_IPV6_MAPPED));
#endif

#ifdef INET6
	stickyopt = inp->inp_outputopts6;
	if (control && v6packet) {
		error = ip6_setpktoptions(control, &opt,
		    ((inp->inp_socket->so_state & SS_PRIV) != 0));
		if (error != 0)
			goto release;
		inp->inp_outputopts6 = &opt;
	}
#endif

	if (addr) {
#ifdef INET6
		sin6 = mtod(addr, struct sockaddr_in6 *);
#endif

	        /*
		 * Save current PCB flags because they may change during
		 * temporary connection, particularly the INP_IPV6_UNDEC
		 * flag.
		 */
                pcbflags = inp->inp_flags;

#ifdef INET6
	        if (inp->inp_flags & INP_IPV6)
			laddr6 = inp->inp_laddr6;
		else
#endif /* INET6 */
			laddr = inp->inp_laddr;
#ifdef INET6
		if (((inp->inp_flags & INP_IPV6) &&
		    !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) ||
		    (inp->inp_faddr.s_addr != INADDR_ANY))
#else /* INET6 */
		if (inp->inp_faddr.s_addr != INADDR_ANY)
#endif /* INET6 */
		{
			error = EISCONN;
			goto release;
		}
		/*
		 * Must block input while temporarily connected.
		 */
		s = splsoftnet();
		error = in_pcbconnect(inp, addr);
		if (error) {
			splx(s);
			goto release;
		}
	} else {
#ifdef INET6
	        if (((inp->inp_flags & INP_IPV6) && 
		    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) ||
		    (inp->inp_faddr.s_addr == INADDR_ANY))
#else /* INET6 */
		if (inp->inp_faddr.s_addr == INADDR_ANY)
#endif /* INET6 */
		{
			error = ENOTCONN;
			goto release;
		}
	}
	/*
	 * Calculate data length and get a mbuf
	 * for UDP and IP headers.
	 */
#ifdef INET6
	/*
	 * Handles IPv4-mapped IPv6 address because temporary connect sets
	 * the right flag.
	 */
	M_PREPEND(m, v6packet ? (sizeof(struct udphdr) +
	    sizeof(struct ip6_hdr)) : sizeof(struct udpiphdr), M_DONTWAIT);
#else /* INET6 */
	M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
#endif /* INET6 */
	if (m == 0) {
		error = ENOBUFS;
		goto bail;
	}

	/*
	 * Compute the packet length of the IP header, and
	 * punt if the length looks bogus.
	 */
	if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
		error = EMSGSIZE;
		goto release;
	}

⌨️ 快捷键说明

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