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

📄 kudp_fastsend.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
字号:
#ifdef	KERNEL/* * Copyright (c) 1987 by Sun Microsystems, Inc. * * @(#)kudp_fastsend.c 1.1 92/07/30 * * Functions to speed up Kernel UDP RPC sending */#include <sys/param.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/errno.h>#include <sys/file.h>#include <net/if.h>#include <net/if_arp.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include <netinet/in_pcb.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/ip_var.h>#include <netinet/in_var.h>#include <netinet/udp.h>#include <netinet/udp_var.h>struct in_ifaddr *ifptoia();/* * struct used to reference count a fragmented mbuf. */struct mhold {	int mh_ref;		/* holders of pointers to mbuf data */	struct mbuf *mh_mbuf;	/* mbuf that owns the data */};staticfragbuf_free(mh)	struct mhold *mh;{	int s;	s = splimp();	if (--mh->mh_ref) {		(void) splx(s);		return;	}	m_freem(dtom(mh));	(void) splx(s);}static struct mhold *fragbuf_alloc(m)	struct mbuf *m;{	struct mbuf *newm;	struct mhold *mh;	MGET(newm, M_WAIT, MT_DATA);	newm->m_next = m;	newm->m_off = MMINOFF;	newm->m_len = 0;	m->m_next = NULL;	mh = mtod(newm, struct mhold *);	mh->mh_ref = 1;	mh->mh_mbuf = m;	return (mh);}extern int Sendtries;extern int Sendok;int route_hit, route_missed;/* * Enough bytes so that the network drivers won't need * to allocate another mbuf near the front of the chain. * Note:  This must be a multiple of sizeof (int)! */#define	KU_PRE_PAD	24ku_sendto_mbuf(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 maxlen;		/* max length of fragment */	register int curlen;		/* data fragment length */	register int fragoff;		/* data fragment offset */	register int grablen;		/* number of mbuf bytes to grab */	register struct ip *ip;		/* ip header */	register struct mbuf *m;	/* ip header mbuf */	int error;			/* error number */	int s;	struct ifnet *ifp;		/* interface */	struct sockaddr_in *dst;	/* packet destination */	struct inpcb *inp;		/* inpcb for binding */	struct ip *nextip;		/* ip header for next fragment */	Sendtries++;	/*	 * Determine length of data.	 * This should be passed in as a parameter.	 */	curlen = 0;	for (m = am; m; m = m->m_next) {		curlen += m->m_len;	}	/*	 * Bind local port if necessary.  This will usually put a route in the	 * pcb, so we just use that one if we have not changed destinations.	 */	inp = sotoinpcb(so);	if ((inp->inp_lport == 0) &&	    (inp->inp_laddr.s_addr == INADDR_ANY))		(void) in_pcbbind(inp, (struct mbuf *) 0);	{		register struct route *ro;		ro = &inp->inp_route;		dst = (struct sockaddr_in *) &ro->ro_dst;		if (ro->ro_rt == 0 || (ro->ro_rt->rt_flags & RTF_UP) == 0 ||		    dst->sin_addr.s_addr != to->sin_addr.s_addr) {			if (ro->ro_rt)				rtfree(ro->ro_rt);			bzero((caddr_t)ro, sizeof (*ro));			ro->ro_dst.sa_family = AF_INET;			dst->sin_addr = to->sin_addr;			rtalloc(ro);			route_missed++;			if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) {				(void) m_freem(am);				return (ENETUNREACH);			}		} else route_hit++;		ifp = ro->ro_rt->rt_ifp;		ro->ro_rt->rt_use++;		if (ro->ro_rt->rt_flags & RTF_GATEWAY) {			dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;		}	}	/*	 * Get mbuf for ip, udp headers.	 */	MGET(m, M_WAIT, MT_HEADER);	if (m == NULL) {		(void) m_freem(am);		return (ENOBUFS);	}	/*	 * XXX on sparc we must pad to make sure that the packet after	 * the ethernet header is int aligned.  Also does not hurt to	 * long-word align on other architectures, and might actually help.	 */	m->m_off = MMINOFF + KU_PRE_PAD;	m->m_len = sizeof (struct ip) + sizeof (struct udphdr);	ip = mtod(m, struct ip *);	/*	 * Create pseudo-header and UDP header, and calculate	 * the UDP level checksum only if desired.	 */	{		extern int	udp_cksum;#define	ui ((struct udpiphdr *)ip)		ui->ui_pr = IPPROTO_UDP;		ui->ui_len = htons((u_short) curlen + sizeof (struct udphdr));		ui->ui_src = ((struct sockaddr_in *)ifptoia(ifp))->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 (udp_cksum) {			ui->ui_next = ui->ui_prev = 0;			ui->ui_x1 = 0;			m->m_next = am;			ui->ui_sum = in_cksum(m,				sizeof (struct udpiphdr) + curlen);			if (ui->ui_sum == 0)				ui->ui_sum = 0xFFFF;		}# undef ui	}	/*	 * Now that the pseudo-header has been checksummed, we can	 * fill in the rest of the IP header except for the IP header	 * checksum, done for each fragment.	 */	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;	/*	 * 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;		register struct mbuf *lam;	/* last mbuf in chain */		/*		 * Assertion: m points to an mbuf containing a mostly filled		 * in ip header, while am points to a chain which contains		 * all the data.		 * The problem here is that there may be too much data.		 * If there is, we have to fragment the data (and maybe the		 * mbuf chain).		 */		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 {			/*			 * Have to fragment the mbuf chain.  am points			 * to the mbuf that has too much, so we take part			 * of its data, point mm to it, and attach mm to			 * the current chain.  lam conveniently points to			 * the last mbuf of the current chain.			 *			 * We will end up with many type 2 mbufs pointing			 * into the data for am. We insure that the data			 * doesn't get freed until all of these mbufs are			 * freed by replacing am with a new type2 mbuf			 * which keeps a ref count and frees am when the			 * count goes to zero.			 */			MGET(mm, M_WAIT, MT_DATA);			if ((int)am->m_clfun != (int)fragbuf_free) {				/*				 * clone the mbuf and save a pointer				 * to it and a ref count.				 */				mm->m_off = mtod(am, int) - (int) mm;				mm->m_len = am->m_len;				mm->m_next = am->m_next;				mm->m_cltype = MCL_LOANED;				mm->m_clswp = NULL;				mm->m_clfun = fragbuf_free;				mm->m_clarg = (int)fragbuf_alloc(am);				am = mm;				MGET(mm, M_WAIT, MT_DATA);			}			grablen = maxlen - curlen;			mm->m_next = NULL;			mm->m_off = mtod(am, int) - (int) mm;			mm->m_len = grablen;			mm->m_cltype = MCL_LOANED;			mm->m_clswp = NULL;			mm->m_clfun = fragbuf_free;			mm->m_clarg = am->m_clarg;			s = splimp();			((struct mhold *)mm->m_clarg)->mh_ref++;			(void) splx(s);			lam->m_next = mm;			am->m_len -= grablen;			am->m_off += grablen;			curlen = maxlen;		}		/*		 * Assertion: m points to an mbuf chain of data which		 * can be sent, while am points to a chain containing		 * all the data that is to be sent in later fragments.		 */		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_HEADER);		if (mm == 0) {			(void) m_free(m);	/* this frag */			(void) m_freem(am);	/* rest of data */			return (ENOBUFS);		}#ifdef sparc		/*		 * XXX on sparc we must pad to make sure that the packet after		 * the ethernet header is int aligned.		 */		mm->m_off =		    MMINOFF + sizeof (short) + sizeof (struct ether_header);#else		mm->m_off = MMINOFF + sizeof (struct ether_header);#endif		mm->m_len = sizeof (struct ip);		nextip = mtod(mm, struct ip *);		bcopy((caddr_t) ip, (caddr_t) nextip, sizeof (struct ip));send:		{			register int sum;			/*			 * Set ip_len and calculate the ip header checksum.			 * Note ips[5] is skipped below since it IS where the			 * checksum will eventually go.			 */			ip->ip_len = (short)			    htons((u_short) (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];			sum = (sum & 0xFFFF) + (sum >> 16);			ip->ip_sum = ~((sum & 0xFFFF) + (sum >> 16));		}#undef ips		/*		 * Send it off to the newtork.		 */		if (error = (*ifp->if_output)(ifp, m, dst)) {			if (am) {				(void) m_freem(am);	/* rest of data */				(void) m_free(mm);	/* hdr for next frag */			}			return (error);		}		if (am == 0) {			/* All fragments sent OK */			Sendok++;			return (0);		}		ip = nextip;		m = mm;		fragoff += curlen;		curlen = 0;	}	/*NOTREACHED*/}#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 ",			ip->ip_hl, ip->ip_v, ip->ip_tos, ip->ip_len,			ip->ip_id, ip->ip_off >> 13, ip->ip_off & 0x1fff);		printf("%d ttl %d p %d sum %d src %x dst %x\n",			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#endif	/* KERNEL */

⌨️ 快捷键说明

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