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

📄 udp_usrreq.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
📖 第 1 页 / 共 2 页
字号:
	    /*	     * 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);}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;#ifdef INET6	if (sa->sa_family == AF_INET6) {		if (ip) {			struct ipv6 *ipv6 = (struct ipv6 *)ip;					uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ipv6));			in6_pcbnotify(&udbtable, sa, uh->uh_dport,			    &(ipv6->ipv6_src), uh->uh_sport, cmd, udp_notify);		} else			in6_pcbnotify(&udbtable, sa, 0,			    (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify);	} 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 ifnet *forceif = 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);#ifndef INET6	if (control)		m_freem(control);		/* XXX */#endif /* INET6 */	if (addr) {	        /*		 * 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.	 */	v6packet = ((inp->inp_flags & INP_IPV6) &&		    !(inp->inp_flags & INP_IPV6_MAPPED));	if (!v6packet && control)		m_freem(control);	M_PREPEND(m, v6packet ? (sizeof(struct udphdr) +	    sizeof(struct ipv6)) : 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;	}	/*	 * Fill in mbuf with extended UDP header	 * and addresses and length put into network format.	 */#ifdef INET6	if (v6packet) {		struct ipv6 *ipv6 = mtod(m, struct ipv6 *);		struct udphdr *uh = (struct udphdr *)(mtod(m, caddr_t) +		    sizeof(struct ipv6));		int payload = sizeof(struct ipv6);		ipv6->ipv6_versfl = htonl(0x60000000) |		    (inp->inp_ipv6.ipv6_versfl & htonl(0x0fffffff)); 	  		ipv6->ipv6_hoplimit = inp->inp_ipv6.ipv6_hoplimit;		ipv6->ipv6_nexthdr = IPPROTO_UDP;		ipv6->ipv6_src = inp->inp_laddr6;		ipv6->ipv6_dst = inp->inp_faddr6;		ipv6->ipv6_length = (u_short)len + sizeof(struct udphdr);		uh->uh_sport = inp->inp_lport;		uh->uh_dport = inp->inp_fport;		uh->uh_ulen = htons(ipv6->ipv6_length);		uh->uh_sum = 0;		if (control)			if ((error = ipv6_controltoheader(&m, control,			    &forceif, &payload)))				goto release;		/* 		 * Always calculate udp checksum for IPv6 datagrams		 */		if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP, len +		    sizeof(struct udphdr), payload))) 			uh->uh_sum = 0xffff;		error = ipv6_output(m, &inp->inp_route6, 		    inp->inp_socket->so_options & SO_DONTROUTE,		    (inp->inp_flags & INP_IPV6_MCAST)?inp->inp_moptions6:NULL,		    forceif, inp->inp_socket);	} 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 /* INET6 */		inp->inp_laddr = laddr;		splx(s);	}	return (error);release:	m_freem(m);	return (error);}u_int	udp_sendspace = 9216;		/* really max datagram size */u_int	udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));					/* 40 1K datagrams *//*ARGSUSED*/intudp_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.ipv6_hoplimit =			    ipv6_defhoplmt;		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();		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;			}		} 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:		in_setsockaddr(inp, addr);		break;	case PRU_PEERADDR:		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) {		printf("udp control data unexpectedly retained\n");		m_freem(control);	}	if (m)		m_freem(m);	return (error);}static voidudp_detach(inp)	struct inpcb *inp;{	int s = splsoftnet();	in_pcbdetach(inp);	splx(s);}/* * Sysctl for udp variables. */intudp_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 */}

⌨️ 快捷键说明

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