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

📄 kudp_fastsend.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
字号:
#ifndef lintstatic	char	*sccsid = "@(#)kudp_fastsend.c	4.2	(ULTRIX)	2/21/91";#endif lint/************************************************************************ *									* *			Copyright (c) 1986 by				* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//* *	Portions of this software have been licensed to  *	Digital Equipment Company, Maynard, MA. *	Copyright (c) 1986 Sun Microsystems, Inc.  ALL RIGHTS RESERVED. * * 20 Feb 91	Uttam Shikarpur *		Counters that were added for network management *		were getting updated improperly. This was fixed. * * 09 May 90	Fred L. Templin *	Changed "m_off" sizing from "sizeof (struct ether_header)" to *	"M_NETPAD" to genericize for various LAN'S. * * 10 Dec 89 -- chet *	Check properly for checksum overflow in ku_fastsend(). * *	24-Oct-89	Uttam Shikarpur *		Made MAXTTL writeable *		Added counters for network management *		1) Number of IP packets sent out (ips_totalsent) *		2) Number of fragments created (ips_totalfrag) *		3) Number of packets fragmented (ips_outpktsfrag) *		 *	30-May-89	U. Sinkewicz *		Replace smp_lock(&so->lk_socket, LK_RETRY) with SO_LOCK *		as part of an smp bug fix.  Fix guarantees that socket  *		doesn't change while unlocked during sleeps or for the *		lock hierarchy. * *	27-Mar-89	U. Sinkewicz *		Reflected ip routing changes (lp 3/16/89). * *	18-Aug-88	condylis *		Added lk_rpcroute SMP lock for static route structure used *		by ku_fastsend.  Added use of lk_rtentry lock in  *		ku_fastsend. * *	21-Jun-88	condylis *		Added interaction with SMP socket lock * *	lp 5-Apr-88 *		Initialize mm to zero as it was getting junk off the *		stack. * *	lp 15-Jan-88 *		Change for malloced mbufs. */#include "../h/param.h"#include "../h/mbuf.h"#include "../h/socket.h"#include "../h/socketvar.h"#include "../h/file.h"/* This group of includes supports nonsmp net devices. 8.9.88.us */#include "../h/cpudata.h"#include "../h/user.h"#include "../h/buf.h"#include "../h/conf.h"#include "../h/proc.h"#include "../net/if.h"#include "../net/route.h"#include "../netinet/in.h"#include "../netinet/if_ether.h"#include "../netinet/in_pcb.h"#include "../netinet/in_var.h"#include "../netinet/in_systm.h"#include "../netinet/ip.h"#include "../netinet/ip_var.h"#include "../netinet/udp.h"#include "../netinet/udp_var.h"#include "../rpc/types.h"#include "../h/errno.h"/* SMP lock for ku_fastsend's static route structure	*/struct lock_t lk_rpcroute;staticbuffree(){}/* * This is the "fast path" to send a UDP packet.  The return value from * ku_fastsend is a little weird: 0 if success, -1 if nonfatal error (the * mbuf chain has not been freed), errno if fatal error (the mbuf chain * has been freed). */ku_fastsend(so, am, to)	struct socket *so;		/* socket data is sent from */	register struct mbuf *am;	/* data to be sent */	struct sockaddr_in *to;		/* destination data is sent to */{	register int datalen;		/* length of all data in packet */	register int maxlen;		/* max length of fragment */	register int curlen;		/* data fragment length */	register int fragoff;		/* data fragment offset */	register int sum;		/* ip header checksum */	register int grablen;		/* number of mbuf bytes to grab */	register struct udpiphdr *ui;	/* udp/ip header */	register struct mbuf *m;	/* ip header mbuf */	struct ip *ip;			/* ip header */	struct ifnet *ifp;		/* interface */	struct mbuf *lam;		/* last mbuf in chain to be sent */	struct sockaddr	*dst;		/* packet destination */	struct inpcb *inp;		/* inpcb for binding */	struct ip *nextip;		/* ip header for next fragment */	static struct route *route[MAXCPU];/* route to send packet */	static struct route zero_route;	/* to initialize route */	int	s;			/* to save spl state	*/	struct in_ifaddr *ia;	struct sockaddr_in *ifaddr;	extern int udpcksum;	int error;	int saveaffinity;	/* supports nonsmp net devices 8.9.88.us */	/*	 * Determine length of data.	 * This should be passed in as a parameter.	 */	datalen = 0;	for (m = am; m; m = m->m_next) {		datalen += m->m_len;	}	/*	 * Routing.	 * We worry about routing early so we get the right ifp.	 */	{		register struct route *ro;		if ((ro = route[CURRENT_CPUDATA->cpu_num]) == NULL) {			kmem_alloc(ro, struct route *, (u_int)sizeof(struct route), KM_RPC);			route[CURRENT_CPUDATA->cpu_num] = ro;		}					s = splnet();		RTLOCK();		if (ro->ro_rt == 0 || (ro->ro_rt->rt_flags & RTF_UP) == 0 ||		    ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr !=		    to->sin_addr.s_addr) {			if (ro->ro_rt) {				rtfree(ro->ro_rt);			}			*ro = zero_route;			ro->ro_dst.sa_family = AF_INET;			((struct sockaddr_in *)&ro->ro_dst)->sin_addr =			    to->sin_addr;			rtalloc(ro);			if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) {				(void) m_freem(am);				RTUNLOCK();				splx(s);				return (ENETUNREACH);			}		}		ifp = ro->ro_rt->rt_ifp;		ro->ro_rt->rt_use++;		if (ro->ro_rt->rt_flags & RTF_GATEWAY) {			dst = &ro->ro_rt->rt_gateway;		} else {			dst = &ro->ro_dst;		}		RTUNLOCK();		splx(s);		s = splnet();		smp_lock(&lk_in_ifaddr, LK_RETRY);		for (ia = in_ifaddr; ia; ia = ia->ia_next)			if (ia->ia_ifp == ifp)				break;		if (ia == 0) {			ia = in_ifaddr;			if (ia == 0) {				smp_unlock(&lk_in_ifaddr);				splx(s);				printf ("ku_fastsend: no interface\n");				return (-1);			}		}		ifaddr = (struct sockaddr_in *)&ia->ia_addr;		smp_unlock(&lk_in_ifaddr);		splx(s);	}	/*	 * Bind port, if necessary.	 */	/* SMP lock is for access to socket structure in sotoinpcb	 * and for call to in_pcbbind 	 */	s = splnet();	SO_LOCK(so);	/* smp_lock(&so->lk_socket, LK_RETRY); */	inp = sotoinpcb(so);	if (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport==0) {		(void)in_pcbbind(inp, (struct mbuf *)0);	}	smp_unlock(&so->lk_socket);	splx(s);	/*	 * Get mbuf for ip, udp headers.	 */	MGET(m, M_WAIT, MT_DATA);	if (m == NULL) {		(void) m_freem(am);		return (ENOBUFS);	}	/*	 * Next statement guarantees longword alignment. This is	 * absolutely required for MIPS...	 */	m->m_off = MMINOFF + M_NETPAD;	m->m_len = sizeof (struct udpiphdr);	m->m_next = am;	/*	 * Create UDP/IP header for checksumming.	 */	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)(datalen + sizeof (struct udphdr)));	ui->ui_src = ifaddr->sin_addr;	ui->ui_dst = to->sin_addr;	ui->ui_sport = inp->inp_lport;	ui->ui_dport = to->sin_port;	ui->ui_ulen = ui->ui_len;	ui->ui_sum = 0;	if(udpcksum)		if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + datalen)) == 0)			ui->ui_sum = -1;	/*	 * Fill in rest of IP header.	 */	ip = (struct ip *)ui;	ip->ip_hl = sizeof (struct ip) >> 2;	ip->ip_v = IPVERSION;	ip->ip_tos = 0;	ip->ip_id = ip_id++;	ip->ip_off = 0;	ip->ip_ttl = maxttl;	ip->ip_sum = 0;	/*	 * Fragment the data into packets big enough for the	 * interface, prepend the header, and send them off.	 */	maxlen = (ifp->if_mtu - sizeof (struct ip)) & ~7;	curlen = sizeof (struct udphdr);	fragoff = 0;	for (;;) {		register struct mbuf *mm = NULL;		register outtotalfrag;   /* for statistics */		register outpktsfrag;    /* for statistics */		/* initialize the counters */		outtotalfrag = 0;		outpktsfrag = 0;		m->m_next = am;		lam = m;		while (am->m_len + curlen <= maxlen) {			curlen += am->m_len;			lam = am;			am = am->m_next;			if (am == 0) {				ip->ip_off = htons((u_short) (fragoff >> 3));				goto send;			}		}		if (curlen == maxlen) {			/*			 * Incredible luck: last mbuf exactly			 * filled out the packet.			 */			lam->m_next = 0;		} else {			/*			 * We can squeeze part of the next			 * mbuf into this packet, so we			 * get a type 2 mbuf and point it at			 * this data fragment.			 */			MGET(mm, M_WAIT, MT_DATA);			if (mm == NULL) {				(void)m_free(m);				mm = dtom(ip);				if (mm != m) {					(void)m_free(mm);				}				printf("ku_sendit: MGET failed\n");				return (-1);			}			grablen = maxlen - curlen;			mm->m_off = mtod(am, int);			mm->m_len = grablen;			mm->m_cltype = 2;			mm->m_clfun = buffree;			mm->m_clswp = NULL;			lam->m_next = mm;			am->m_len -= grablen;			am->m_off += grablen;			curlen = maxlen;		}		/*		 * m now points to the head of an mbuf chain which		 * contains the max amount that can be sent in a packet.		 */		ip->ip_off = htons((u_short) ((fragoff >> 3) | IP_MF));		/*		 * There are more frags, so we save		 * a copy of the ip hdr for the next		 * frag.		 */		MGET(mm, M_WAIT, MT_DATA);		if (mm == 0) {			(void)m_free(dtom(ip));			printf("ku_sendit: MGET failed\n");			return (-1);		}		/*		 * Next statement guarantees longword alignment. This is		 * absolutely required for MIPS...		 */		mm->m_off = MMINOFF + M_NETPAD;		mm->m_len = sizeof (struct ip);		nextip = mtod(mm, struct ip *);		*nextip = *ip;send:		/*		 * Set ip_len and calculate the ip header checksum.		 */		ip->ip_len = htons(sizeof (struct ip) + curlen);#define	ips ((u_short *) ip)		sum = ips[0] + ips[1] + ips[2] + ips[3] + ips[4] + ips[6] +			ips[7] + ips[8] + ips[9];		/* now, handle sum (16 bit) overflows correctly */		if (sum > 0xffff) {			sum = (0xffff & sum) + (sum >> 16);			if (sum > 0xffff)				sum = (0xffff & sum) + (sum >> 16);		}		ip->ip_sum = ~sum;#undef ips		/*		 * At last, we send it off to the ethernet.		 * Before we send this off to the ethernet		 * we make local copies of the statistics		 * that need to be updated. After the packet		 * has been sent we actually update it.		 * REASON: The updating requires refrencing		 * the mbuf, which gets freed once the packet		 * has been sent.		 */		if (ip->ip_off & IP_MF) {			/* bump up the # of fragments created */			outtotalfrag++;			/* The number of packets fragmented should			 * be bumped only once in the for() loop.			 * "fragoff" is used to prevent bumping the			 * counter more than once.			 */			if (fragoff == 0) /* a packet was fragmented */				outpktsfrag++;			/* This is added to include the last fragment that			 * is sent. It will not have the IP_MF flag set.			 */			 if (!(ip->ip_off & IP_MF) && fragoff != 0) {				/* bump up the fragmentation count */				outpktsfrag++;			 }		}		CALL_TO_NONSMP_DRIVER( (*ifp), saveaffinity);		error = (*ifp->if_output)(ifp, m, dst);		RETURN_FROM_NONSMP_DRIVER( (*ifp), saveaffinity);		if (error) {			printf("ku_fastsend: transmit failed on %s%d, errno %d\n", 				ifp->if_name, ifp->if_unit, error);			if (am)				m_free(am);			if (mm)				m_freem(mm);			if (error < 0)				error = EIO;			return (error);		} else { /* bump up counters for network management */			IPSTAT(ips_totalsent++);			/* check for fragmentation */			if (outtotalfrag) {				/* bump up the # of fragments created */				IPSTAT(ips_outtotalfrag += outtotalfrag);			} 			/* check if a packet was fragmented */			if (outpktsfrag) {				/* bump up the # of pkts. fragmented */				IPSTAT(ips_outpktsfrag += outpktsfrag);			}		}						if (am == 0) {			return (0);		}		ip = nextip;		m = dtom(ip);		mm = NULL;		fragoff += curlen;		curlen = 0;	}}#ifdef DEBUGpr_mbuf(p, m)	char *p;	struct mbuf *m;{	register char *cp, *cp2;	register struct ip *ip;	register int len;	len = 28;	printf("%s: ", p);	if (m && m->m_len >= 20) {		ip = mtod(m, struct ip *);		printf("hl %d v %d tos %d len %d id %d mf %d off %d ttl %d p %d sum %d src %x dst %x\n",			ip->ip_hl, ip->ip_v, ip->ip_tos, ip->ip_len,			ip->ip_id, ip->ip_off >> 13, ip->ip_off & 0x1fff,			ip->ip_ttl, ip->ip_p, ip->ip_sum, ip->ip_src.s_addr,			ip->ip_dst.s_addr);		len = 0;		printf("m %x addr %x len %d\n", m, mtod(m, caddr_t), m->m_len);		m = m->m_next;	} else if (m) {		printf("pr_mbuf: m_len %d\n", m->m_len);	} else {		printf("pr_mbuf: zero m\n");	}	while (m) {		printf("m %x addr %x len %d\n", m, mtod(m, caddr_t), m->m_len);		cp = mtod(m, caddr_t);		cp2 = cp + m->m_len;		while (cp < cp2) {			if (len-- < 0) {				break;			}			printf("%x ", *cp & 0xFF);			cp++;		}		m = m->m_next;		printf("\n");	}}#endif DEBUG

⌨️ 快捷键说明

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