udp_usrreq.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,375 行 · 第 1/3 页

C
1,375
字号
					    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 voidudp_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)voidudp6_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);}#endifvoid *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, ...)#elseudp_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 + =
减小字号Ctrl + -
显示快捷键?