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

📄 udp_usrreq.c

📁 嵌入式操作系统ECOS的网络开发包
💻 C
📖 第 1 页 / 共 3 页
字号:

	/*
	 * Fill in mbuf with extended UDP header
	 * and addresses and length put into network format.
	 */
#ifdef INET6
	if (v6packet) {
		struct ip6_hdr *ipv6 = mtod(m, struct ip6_hdr *);
		struct udphdr *uh = (struct udphdr *)(mtod(m, caddr_t) +
		    sizeof(struct ip6_hdr));
		int payload = sizeof(struct ip6_hdr);
		struct in6_addr *faddr;
		struct in6_addr *laddr;
		struct ifnet *oifp = NULL;

		ipv6->ip6_flow = htonl(0x60000000) |
		    (inp->inp_ipv6.ip6_flow & htonl(0x0fffffff)); 
	  
		ipv6->ip6_nxt = IPPROTO_UDP;
		ipv6->ip6_dst = inp->inp_faddr6;
		/*
		 * If the scope of the destination is link-local,
		 * embed the interface
		 * index in the address.
		 *
		 * XXX advanced-api value overrides sin6_scope_id 
		 */
		faddr = &ipv6->ip6_dst;
		if (IN6_IS_ADDR_LINKLOCAL(faddr) ||
		    IN6_IS_ADDR_MC_LINKLOCAL(faddr)) {
			struct ip6_pktopts *optp = inp->inp_outputopts6;
			struct in6_pktinfo *pi = NULL;
			struct ip6_moptions *mopt = NULL;

			/*
			 * XXX Boundary check is assumed to be already done in
			 * ip6_setpktoptions().
			 */
			if (optp && (pi = optp->ip6po_pktinfo) &&
			    pi->ipi6_ifindex) {
				faddr->s6_addr16[1] = htons(pi->ipi6_ifindex);
				oifp = ifindex2ifnet[pi->ipi6_ifindex];
			}
			else if (IN6_IS_ADDR_MULTICAST(faddr) &&
				 (mopt = inp->inp_moptions6) &&
				 mopt->im6o_multicast_ifp) {
				oifp = mopt->im6o_multicast_ifp;
				faddr->s6_addr16[1] = oifp->if_index;
			} else if (sin6 && sin6->sin6_scope_id) {
				/* boundary check */
				if (sin6->sin6_scope_id < 0 
				    || if_index < sin6->sin6_scope_id) {
					error = ENXIO;  /* XXX EINVAL? */
					goto release;
				}
				/* XXX */
				faddr->s6_addr16[1] =
					htons(sin6->sin6_scope_id & 0xffff);
			}
		}
		ipv6->ip6_hlim = in6_selecthlim(inp, oifp);
		if (sin6) {	/*XXX*/
			laddr = in6_selectsrc(sin6, inp->inp_outputopts6,
					      inp->inp_moptions6,
					      &inp->inp_route6,
					      &inp->inp_laddr6, &error);
			if (laddr == NULL) {
				if (error == 0)
					error = EADDRNOTAVAIL;
				goto release;
			}
		} else
			laddr = &inp->inp_laddr6;

		ipv6->ip6_src = *laddr;

		ipv6->ip6_plen = (u_short)len + sizeof(struct udphdr);

		uh->uh_sport = inp->inp_lport;
		uh->uh_dport = inp->inp_fport;
		uh->uh_ulen = htons(ipv6->ip6_plen);
		uh->uh_sum = 0;

		/* 
		 * Always calculate udp checksum for IPv6 datagrams
		 */
		if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP,
		    payload, len + sizeof(struct udphdr))))
			uh->uh_sum = 0xffff;

		error = ip6_output(m, inp->inp_outputopts6, &inp->inp_route6, 
		    inp->inp_socket->so_options & SO_DONTROUTE,
		    (inp->inp_flags & INP_IPV6_MCAST)?inp->inp_moptions6:NULL,
		    NULL);
	} else
#endif /* INET6 */
	{
		ui = mtod(m, struct udpiphdr *);
		bzero(ui->ui_x1, sizeof ui->ui_x1);
		ui->ui_pr = IPPROTO_UDP;
		ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
		ui->ui_src = inp->inp_laddr;
		ui->ui_dst = inp->inp_faddr;
		ui->ui_sport = inp->inp_lport;
		ui->ui_dport = inp->inp_fport;
		ui->ui_ulen = ui->ui_len;

		/*
		 * Stuff checksum and output datagram.
		 */

		ui->ui_sum = 0;
		if (udpcksum) {
			if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) +
			    len)) == 0)
				ui->ui_sum = 0xffff;
		}
		((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
#ifdef INET6
		/*
		 *  For now, we use the default values for ttl and tos for 
		 *  v4 packets sent using a v6 pcb.  We probably want to
		 *  later allow v4 setsockopt operations on a v6 socket to 
		 *  modify the ttl and tos for v4 packets sent using
		 *  the mapped address format.  We really ought to
		 *  save the v4 ttl and v6 hoplimit in separate places 
		 *  instead of craming both in the inp_hu union.
		 */
		if (inp->inp_flags & INP_IPV6) {
			((struct ip *)ui)->ip_ttl = ip_defttl;
			((struct ip *)ui)->ip_tos = 0;	  
		} else
#endif /* INET6 */
		{
			((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl;	
			((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos;
		}

		udpstat.udps_opackets++;
#ifdef INET6
		if (inp->inp_flags & INP_IPV6_MCAST) {
			error = ip_output(m, inp->inp_options, &inp->inp_route,
				inp->inp_socket->so_options &
				(SO_DONTROUTE | SO_BROADCAST),
				NULL, NULL, inp->inp_socket);
		} else
#endif /* INET6 */
		{
			error = ip_output(m, inp->inp_options, &inp->inp_route,
				inp->inp_socket->so_options &
				(SO_DONTROUTE | SO_BROADCAST),
		    		inp->inp_moptions, inp, NULL);
		}
	}

bail:
	if (addr) {
		in_pcbdisconnect(inp);
                inp->inp_flags = pcbflags;
#ifdef INET6
		if (inp->inp_flags & INP_IPV6)
			inp->inp_laddr6 = laddr6;
	        else
#endif
			inp->inp_laddr = laddr;
		splx(s);
	}
	if (control) {
#ifdef INET6
		if (v6packet)
			inp->inp_outputopts6 = stickyopt;
#endif
		m_freem(control);
	}
	return (error);

release:
	m_freem(m);
	if (control) {
#ifdef INET6
		if (v6packet)
			inp->inp_outputopts6 = stickyopt;
#endif
		m_freem(control);
	}
	return (error);
}

u_int	udp_sendspace = 9216;		/* really max datagram size */
u_int	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
					/* 40 1K datagrams */

#if defined(INET6) && !defined(TCP6)
/*ARGSUSED*/
int
udp6_usrreq(so, req, m, addr, control, p)
	struct socket *so;
	int req;
	struct mbuf *m, *addr, *control;
	struct proc *p;
{
	return udp_usrreq(so, req, m, addr, control);
}
#endif

/*ARGSUSED*/
int
udp_usrreq(so, req, m, addr, control)
	struct socket *so;
	int req;
	struct mbuf *m, *addr, *control;
{
	struct inpcb *inp = sotoinpcb(so);
	int error = 0;
	int s;

	if (req == PRU_CONTROL) {
#ifdef INET6
		if (inp->inp_flags & INP_IPV6)
			return (in6_control(so, (u_long)m, (caddr_t)addr,
			    (struct ifnet *)control, 0));
		else
#endif /* INET6 */
			return (in_control(so, (u_long)m, (caddr_t)addr,
			    (struct ifnet *)control));
	}
	if (inp == NULL && req != PRU_ATTACH) {
		error = EINVAL;
		goto release;
	}
	/*
	 * Note: need to block udp_input while changing
	 * the udp pcb queue and/or pcb addresses.
	 */
	switch (req) {

	case PRU_ATTACH:
		if (inp != NULL) {
			error = EINVAL;
			break;
		}
		s = splsoftnet();
		error = in_pcballoc(so, &udbtable);
		splx(s);
		if (error)
			break;
		error = soreserve(so, udp_sendspace, udp_recvspace);
		if (error)
			break;
#ifdef INET6
		if (((struct inpcb *)so->so_pcb)->inp_flags & INP_IPV6)
			((struct inpcb *) so->so_pcb)->inp_ipv6.ip6_hlim =
			    ip6_defhlim;
		else
#endif /* INET6 */
			((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
		break;

	case PRU_DETACH:
		udp_detach(inp);
		break;

	case PRU_BIND:
		s = splsoftnet();
#ifdef INET6
		if (inp->inp_flags & INP_IPV6)
			error = in6_pcbbind(inp, addr);
		else
#endif
			error = in_pcbbind(inp, addr);
		splx(s);
		break;

	case PRU_LISTEN:
		error = EOPNOTSUPP;
		break;

	case PRU_CONNECT:
#ifdef INET6 
		if (inp->inp_flags & INP_IPV6) {
			if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
				error = EISCONN;
				break;
			}
			s = splsoftnet();
			error = in6_pcbconnect(inp, addr);
			splx(s);
		} else
#endif /* INET6 */
		{
			if (inp->inp_faddr.s_addr != INADDR_ANY) {
				error = EISCONN;
				break;
			}
			s = splsoftnet();
			error = in_pcbconnect(inp, addr);
			splx(s);
		}

		if (error == 0)
			soisconnected(so);
		break;

	case PRU_CONNECT2:
		error = EOPNOTSUPP;
		break;

	case PRU_ACCEPT:
		error = EOPNOTSUPP;
		break;

	case PRU_DISCONNECT:
#ifdef INET6 
		if (inp->inp_flags & INP_IPV6) {
			if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
				error = ENOTCONN;
				break;
			}
		} else
#endif /* INET6 */
			if (inp->inp_faddr.s_addr == INADDR_ANY) {
				error = ENOTCONN;
				break;
			}

		s = splsoftnet();
		in_pcbdisconnect(inp);
#ifdef INET6
		if (inp->inp_flags & INP_IPV6)
			inp->inp_laddr6 = in6addr_any;
		else
#endif /* INET6 */
			inp->inp_laddr.s_addr = INADDR_ANY;

		splx(s);
		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
		break;

	case PRU_SHUTDOWN:
		socantsendmore(so);
		break;

	case PRU_SEND:
#ifdef IPSEC
		error = check_ipsec_policy(inp,0);
		if (error)
			return (error);
#endif
		return (udp_output(m, inp, addr, control));

	case PRU_ABORT:
		soisdisconnected(so);
		udp_detach(inp);
		break;

	case PRU_SOCKADDR:
#ifdef INET6
		if (inp->inp_flags & INP_IPV6)
			in6_setsockaddr(inp, addr);
		else
#endif /* INET6 */
			in_setsockaddr(inp, addr);
		break;

	case PRU_PEERADDR:
#ifdef INET6
		if (inp->inp_flags & INP_IPV6)
			in6_setpeeraddr(inp, addr);
		else
#endif /* INET6 */
			in_setpeeraddr(inp, addr);
		break;

	case PRU_SENSE:
		/*
		 * stat: don't bother with a blocksize.
		 */
		/*
		 * Perhaps Path MTU might be returned for a connected
		 * UDP socket in this case.
		 */
		return (0);

	case PRU_SENDOOB:
	case PRU_FASTTIMO:
	case PRU_SLOWTIMO:
	case PRU_PROTORCV:
	case PRU_PROTOSEND:
		error =  EOPNOTSUPP;
		break;

	case PRU_RCVD:
	case PRU_RCVOOB:
		return (EOPNOTSUPP);	/* do not free mbuf's */

	default:
		panic("udp_usrreq");
	}

release:
	if (control) {
#ifdef __ECOS
		diag_printf("udp control data unexpectedly retained\n");
#else
		printf("udp control data unexpectedly retained\n");
#endif
		m_freem(control);
	}
	if (m)
		m_freem(m);
	return (error);
}

static void
udp_detach(inp)
	struct inpcb *inp;
{
	int s = splsoftnet();

	in_pcbdetach(inp);
	splx(s);
}

#ifdef CYGPKG_NET_SYSCTL
/*
 * Sysctl for udp variables.
 */
int
udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
	int *name;
	u_int namelen;
	void *oldp;
	size_t *oldlenp;
	void *newp;
	size_t newlen;
{
	/* All sysctl names at this level are terminal. */
	if (namelen != 1)
		return (ENOTDIR);

	switch (name[0]) {
	case UDPCTL_CHECKSUM:
		return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
	case UDPCTL_BADDYNAMIC:
		return (sysctl_struct(oldp, oldlenp, newp, newlen,
		    baddynamicports.udp, sizeof(baddynamicports.udp)));
	case UDPCTL_RECVSPACE:
		return (sysctl_int(oldp, oldlenp, newp, newlen,&udp_recvspace));
	case UDPCTL_SENDSPACE:
		return (sysctl_int(oldp, oldlenp, newp, newlen,&udp_sendspace));
	default:
		return (ENOPROTOOPT);
	}
	/* NOTREACHED */
}
#endif // CYGPKG_NET_SYSCTL

⌨️ 快捷键说明

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