udp_usrreq.c

来自「操作系统SunOS 4.1.3版本的源码」· C语言 代码 · 共 419 行

C
419
字号
#ifndef lintstatic        char sccsid[] = "@(#)udp_usrreq.c 1.1 92/07/30 Copyr 1983 Sun Micro";#endif#include <sys/param.h>#include <sys/dir.h>#include <sys/user.h>#include <sys/mbuf.h>#include "boot/protosw.h"#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/errno.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_pcb.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/ip_var.h>#include <netinet/ip_icmp.h>#include <netinet/udp.h>#include <netinet/udp_var.h>static int dump_debug = 10;/* * UDP protocol implementation. * Per RFC 768, August, 1980. */udp_init(){	udb.inp_next = udb.inp_prev = &udb;}int	udpcksum = 0;struct	sockaddr_in udp_in = { AF_INET };udp_input(m0)	struct mbuf *m0;{	register struct udpiphdr *ui;	register struct inpcb *inp;	register struct mbuf *m;	int len;	/*	 * Get IP and UDP header together in first mbuf.	 */	m = m0;	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&	    (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {		udpstat.udps_hdrops++;		return;	}	ui = mtod(m, struct udpiphdr *);#ifdef	NEVER	if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))		ip_stripoptions((struct ip *)ui, (struct mbuf *)0);#endif	/* NEVER */	/*	 * Make mbuf data length reflect UDP length.	 * If not enough data to reflect UDP length, drop.	 */	len = ntohs((u_short)ui->ui_ulen);	if (((struct ip *)ui)->ip_len != len) {		if (len > ((struct ip *)ui)->ip_len) {			udpstat.udps_badlen++;			goto bad;		}		m_adj(m, len - ((struct ip *)ui)->ip_len);		/* (struct ip *)ui->ip_len = len; */	}	/*	 * Checksum extended UDP header and data.	 */	if (udpcksum && ui->ui_sum) {		ui->ui_next = ui->ui_prev = 0;		ui->ui_x1 = 0;		ui->ui_len = htons((u_short)len);		if (ui->ui_sum = ipcksum((char *)&(ui->ui_sport),		    (unsigned short)(len + sizeof (struct ip)))) {			dprint(dump_debug, 6,				"udp_input: bad checksum 0x%x\n",				ui->ui_sum);			udpstat.udps_badsum++;			m_freem(m);			return;		}	}	/*	 * Locate pcb for datagram.	 */	inp = in_pcblookup(&udb,	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,		INPLOOKUP_WILDCARD);	if (inp == 0) {		/* don't send ICMP response for broadcast packet */		if (in_lnaof(ui->ui_dst) == INADDR_ANY)			goto bad;#ifdef	NEVER		icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT);#endif	/* NEVER */		return;	}	/*	 * Construct sockaddr format source address.	 * Stuff source address and datagram in user buffer.	 */	udp_in.sin_port = ui->ui_sport;	udp_in.sin_addr = ui->ui_src;	m->m_len -= sizeof (struct udpiphdr);	m->m_off += sizeof (struct udpiphdr);	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,	    m, (struct mbuf *)0,	    inp->inp_socket->so_proto->pr_flags & PR_RIGHTS) == 0) {		udpstat.udps_fullsock++;		goto bad;	}#ifdef	NEVER	sorwakeup(inp->inp_socket);#endif	/* NEVER */	return;bad:	dprint(dump_debug, 6,		"udp_input: bad\n");	m_freem(m);}udp_abort(inp)	struct inpcb *inp;{#ifdef	NEVER	struct socket *so = inp->inp_socket;	in_pcbdisconnect(inp);	soisdisconnected(so);#endif	/* NEVER */}udp_ctlinput(cmd, arg)	int cmd;	caddr_t arg;{#ifdef	NEVER	struct in_addr *sin;	extern u_char inetctlerrmap[];	if (cmd < 0 || cmd > PRC_NCMDS)		return;	switch (cmd) {	case PRC_ROUTEDEAD:		break;	case PRC_QUENCH:		break;	/* these are handled by ip */	case PRC_IFDOWN:	case PRC_HOSTDEAD:	case PRC_HOSTUNREACH:		break;	default:		sin = &((struct icmp *)arg)->icmp_ip.ip_dst;		in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort);	}#endif	/* NEVER */}int udp_fastloop = 1;	/* udp fast loopback enabled */udp_output(inp, m0)	struct inpcb *inp;	struct mbuf *m0;{#ifdef	NEVER	register struct mbuf *m;	register struct udpiphdr *ui;	register struct socket *so;	register int len = 0;	int flags;	/*	 * Calculate data length and get a mbuf	 * for UDP and IP headers.	 */	for (m = m0; m; m = m->m_next)		len += m->m_len;	m = m_get(M_DONTWAIT, MT_HEADER);	if (m == 0) {		m_freem(m0);		return (ENOBUFS);	}	/*	 * Fill in mbuf with extended UDP header	 * and addresses and length put into network format.	 */	m->m_off = MMAXOFF - sizeof (struct udpiphdr);	m->m_len = sizeof (struct udpiphdr);	m->m_next = m0;	ui = mtod(m, struct udpiphdr *);	ui->ui_next = ui->ui_prev = 0;	ui->ui_x1 = 0;	ui->ui_pr = IPPROTO_UDP;	ui->ui_len = htons((u_short)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 = (u_short)ui->ui_len;	((struct ip *)ui)->ip_hl = sizeof (struct ip) >> 2;	/*	 * Stuff checksum and output datagram.	 */	ui->ui_sum = 0;	if (udpcksum && 	    (ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)		ui->ui_sum = -1;	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;	((struct ip *)ui)->ip_ttl = MAXTTL;	so = inp->inp_socket;	flags = (so->so_options & SO_DONTROUTE) | (so->so_state & SS_PRIV);	if (udp_fastloop) {		/*		 * Check for loopback by checking whether we		 * have an interface to the destination.		 */		if (ifnet && ifnet->if_addr.sa_family == AF_INET &&		    ((struct sockaddr_in *) &ifnet->if_addr)->sin_addr.s_addr		    == ui->ui_dst.s_addr) {			if (ui->ui_src.s_addr == 0) {				ui->ui_src.s_addr = ui->ui_dst.s_addr;			}			((struct ip *)ui)->ip_len -= sizeof (struct ipovly);			udp_input(m);			return (0);		}	}	return (ip_output(m, (struct mbuf *)0, (struct route *)0, flags));#endif	/* NEVER */}/*ARGSUSED*/udp_usrreq(so, req, m, nam, rights)	struct socket *so;	int req;	struct mbuf *m, *nam, *rights;{	struct inpcb *inp = sotoinpcb(so);	int error = 0;	/*	 * XXX Protect udp_usrreq just like tcp.	 * Avoids race condition with in_pcballoc;	 * also keeps icmp error from aborting a udp	 * socket that is not connected (sendto used).	 */	int s;	s = splnet();	if (rights && rights->m_len) {		error = EINVAL;		goto release;	}	if (inp == NULL && req != PRU_ATTACH) {		error = EINVAL;		goto release;	}	switch (req) {	case PRU_ATTACH:		if (inp != NULL) {			error = EINVAL;			break;		}		error = in_pcballoc(so, &udb);		if (error)			break;		/* udp delivers data + sockaddr, must make space */		error = soreserve(so, 9000, 9000 + sizeof(struct sockaddr));		if (error)			break;		break;#ifdef	NEVER	case PRU_DETACH:		if (inp == NULL) {			error = ENOTCONN;			break;		}		in_pcbdetach(inp);		break;#endif	/* NEVER */	case PRU_BIND:		error = in_pcbbind(inp, nam);		break;#ifdef	NEVER	case PRU_LISTEN:		error = EOPNOTSUPP;		break;	case PRU_CONNECT:		if (inp->inp_faddr.s_addr != INADDR_ANY) {			error = EISCONN;			break;		}		error = in_pcbconnect(inp, nam);		if (error == 0)			soisconnected(so);		break;	case PRU_CONNECT2:		error = EOPNOTSUPP;		break;	case PRU_ACCEPT:		error = EOPNOTSUPP;		break;	case PRU_DISCONNECT:		if (inp->inp_faddr.s_addr == INADDR_ANY) {			error = ENOTCONN;			break;		}		in_pcbdisconnect(inp);		soisdisconnected(so);		break;	case PRU_SHUTDOWN:		socantsendmore(so);		break;	case PRU_SEND:	    {		struct in_addr laddr;		if (nam) {			laddr = inp->inp_laddr;			if (inp->inp_faddr.s_addr != INADDR_ANY) {				error = EISCONN;				break;			}			error = in_pcbconnect(inp, nam);			if (error)				break;		} else {			if (inp->inp_faddr.s_addr == INADDR_ANY) {				error = ENOTCONN;				break;			}		}		error = udp_output(inp, m);		m = NULL;		if (nam) {			in_pcbdisconnect(inp);			inp->inp_laddr = laddr;		}	    }		break;	case PRU_ABORT:		in_pcbdetach(inp);		sofree(so);		soisdisconnected(so);		break;	case PRU_SOCKADDR:		in_setsockaddr(inp, nam);		break;	case PRU_PEERADDR:		in_setpeeraddr(inp, nam);		break;	case PRU_CONTROL:		m = NULL;		error = EOPNOTSUPP;		break;	case PRU_SENSE:		m = NULL;		/* fall thru... */#endif	/* NEVER */	case PRU_RCVD:	case PRU_RCVOOB:	case PRU_SENDOOB:	case PRU_FASTTIMO:	case PRU_SLOWTIMO:	case PRU_PROTORCV:	case PRU_PROTOSEND:		error =  EOPNOTSUPP;		break;	default:		panic("udp_usrreq");	}release:	(void)splx(s);	if (m != NULL)		m_freem(m);	return (error);}

⌨️ 快捷键说明

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