xref: /csrg-svn/sys/news3400/if/if_news.c (revision 63305)
153897Smckusick /*
2*63305Sbostic  * Copyright (c) 1992, 1993
3*63305Sbostic  *	The Regents of the University of California.  All rights reserved.
453897Smckusick  *
553897Smckusick  * This code is derived from software contributed to Berkeley by
653897Smckusick  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
753897Smckusick  *
853897Smckusick  * %sccs.include.redist.c%
953897Smckusick  *
1053897Smckusick  * from: $Hdr: if_news.c,v 4.300 91/06/09 06:26:01 root Rel41 $ SONY
1153897Smckusick  *
12*63305Sbostic  *	@(#)if_news.c	8.1 (Berkeley) 06/11/93
1353897Smckusick  */
1453897Smckusick 
1557614Sutashiro #include <sys/types.h>
1657180Sutashiro #include <machine/pte.h>
1753897Smckusick 
1857180Sutashiro #include <sys/param.h>
1957180Sutashiro #include <sys/systm.h>
2057180Sutashiro #include <sys/mbuf.h>
2157180Sutashiro #include <sys/map.h>
2257180Sutashiro #include <sys/buf.h>
2357180Sutashiro #include <sys/socket.h>
2457180Sutashiro #include <sys/proc.h>
2557180Sutashiro #include <sys/user.h>
2653897Smckusick 
2757614Sutashiro #include <net/if.h>
2857180Sutashiro #include <news3400/if/if_news.h>
2957180Sutashiro #include <machine/cpu.h>
3053897Smckusick 
3153897Smckusick #if MCLBYTES == CLBYTES && defined(CPU_DOUBLE)
3253897Smckusick #define	USE_CLUSTER
3353897Smckusick #endif
3453897Smckusick 
3553897Smckusick /*
3653897Smckusick  * Routines supporting NEWS network interfaces.
3753897Smckusick  */
3853897Smckusick #define btomcl(x)       (((x) + MCLBYTES - 1) >> MCLSHIFT)
3953897Smckusick 
4053897Smckusick /*
4153897Smckusick  * Init NEWS for interface on uban whose headers of size hlen are to
4253897Smckusick  * end on a page boundary.  We also allocate page frames in the mbuffer pool
4353897Smckusick  * for these pages.
4453897Smckusick  */
if_newsinit(ifn,hlen,nmr)4553897Smckusick if_newsinit(ifn, hlen, nmr)
4653897Smckusick 	register struct ifnews *ifn;
4753897Smckusick 	int hlen, nmr;
4853897Smckusick {
4953897Smckusick #ifdef USE_CLUSTER
5053897Smckusick 	register caddr_t cp;
5153897Smckusick 	int ncl;
5253897Smckusick 
5353897Smckusick 	if (ifn->ifn_raddr)
5453897Smckusick 		return (1);
5553897Smckusick 	ncl = nmr;
5653897Smckusick 	cp = malloc(btomcl(ctob(2 * ncl)), M_DEVBUF, M_NOWAIT); /*XXX*/
5753897Smckusick 	if (cp == 0)
5853897Smckusick 		return (0);
5953897Smckusick 	ifn->ifn_raddr = cp + 4 - (hlen & 03);
6053897Smckusick 	ifn->ifn_waddr = cp + ncl * MCLBYTES;
6153897Smckusick #endif /* USE_CLUSTER */
6253897Smckusick 	ifn->ifn_hlen = hlen;
6353897Smckusick 	return (1);
6453897Smckusick }
6553897Smckusick 
6653897Smckusick /*
6753897Smckusick  * Pull read data off a interface.
6853897Smckusick  * Len is length of data, with local net header stripped.
6953897Smckusick  * Off is non-zero if a trailer protocol was used, and
7053897Smckusick  * gives the offset of the trailer information.
7153897Smckusick  * We copy the trailer information and then all the normal
7253897Smckusick  * data into mbufs.  When large sized units are present
7353897Smckusick  * on the interface on cluster boundaries we can get them more
7453897Smckusick  * easily by remapping, and take advantage of this here.
7553897Smckusick  */
7653897Smckusick #ifdef NOTDEF /* use m_devget */
7753897Smckusick struct mbuf *
if_rnewsget(ifn,totlen,off,ifp)7853897Smckusick if_rnewsget(ifn, totlen, off, ifp)
7953897Smckusick 	register struct ifnews *ifn;
8053897Smckusick 	register int totlen, off;
8153897Smckusick 	struct ifnet *ifp;
8253897Smckusick {
8353897Smckusick 	register struct mbuf **mp, *m;
8453897Smckusick 	struct mbuf *top;
8553897Smckusick 	register int len;
8653897Smckusick 	register caddr_t cp = ifn->ifn_raddr + ifn->ifn_hlen;
8753897Smckusick 	caddr_t epkt = cp + totlen;
8853897Smckusick 
8953897Smckusick #ifdef USE_CLUSTER
9053897Smckusick 	if (totlen >= MHLEN && off == 0) {
9153897Smckusick 		MGETHDR(m, M_DONTWAIT, MT_DATA);
9253897Smckusick 		if (m == 0)
9353897Smckusick 			return (0);
9453897Smckusick 		m->m_pkthdr.rcvif = ifp;
9553897Smckusick 		m->m_pkthdr.len = totlen;
9653897Smckusick 		MCLGET(m, M_DONTWAIT);
9753897Smckusick 		if (m->m_len != MCLBYTES) {
9853897Smckusick 			struct mbuf *n;
9953897Smckusick 
10053897Smckusick 			MFREE(m, n);
10153897Smckusick 			goto noncluster;
10253897Smckusick 		}
10353897Smckusick 		pageswap(cp - ifn->ifn_hlen, mtod(m, caddr_t),
10453897Smckusick 		    totlen + ifn->ifn_hlen);
10553897Smckusick 		m->m_len = totlen;
10653897Smckusick 		m->m_data += ifn->ifn_hlen + 4 - (ifn->ifn_hlen & 03);
10753897Smckusick 		return (m);
10853897Smckusick 	}
10953897Smckusick noncluster:
11053897Smckusick #endif /* USE_CLUSTER */
11153897Smckusick 	top = 0;
11253897Smckusick 	mp = &top;
11353897Smckusick 	/*
11453897Smckusick 	 * Skip the trailer header (type and trailer length).
11553897Smckusick 	 */
11653897Smckusick 	if (off) {
11753897Smckusick 		off += 2 * sizeof(u_short);
11853897Smckusick 		totlen -= 2 * sizeof(u_short);
11953897Smckusick 		cp += off;
12053897Smckusick 	}
12153897Smckusick 	MGETHDR(m, M_DONTWAIT, MT_DATA);
12253897Smckusick 	if (m == 0)
12353897Smckusick 		return ((struct mbuf *)NULL);
12453897Smckusick 	m->m_pkthdr.rcvif = ifp;
12553897Smckusick 	m->m_pkthdr.len = totlen;
12653897Smckusick 	m->m_len = MHLEN;
12753897Smckusick 
12853897Smckusick 	while (totlen > 0) {
12953897Smckusick 		if (top) {
13053897Smckusick 			MGET(m, M_DONTWAIT, MT_DATA);
13153897Smckusick 			if (m == 0) {
13253897Smckusick 				m_freem(top);
13353897Smckusick 				return(0);
13453897Smckusick 			}
13553897Smckusick 			m->m_len = MLEN;
13653897Smckusick 		}
13753897Smckusick 
13853897Smckusick 		if (totlen >= MINCLSIZE)
13953897Smckusick 			MCLGET(m, M_DONTWAIT);
14053897Smckusick 		if (m->m_flags & M_EXT)
14155764Sbostic 			m->m_len = min(totlen, MCLBYTES);
14253897Smckusick 		else if (totlen < m->m_len) {
14353897Smckusick 			/*
14453897Smckusick 			 * Place initial small packet/header at end of mbuf.
14553897Smckusick 			 */
14653897Smckusick 			if (top == 0 && totlen + max_linkhdr <= m->m_len)
14753897Smckusick 				m->m_data += max_linkhdr;
14853897Smckusick 			m->m_len = totlen;
14953897Smckusick 		}
15053897Smckusick 		len = m->m_len;
15153897Smckusick copy:
15253897Smckusick 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
15353897Smckusick 		cp += len;
15453897Smckusick nocopy:
15553897Smckusick 		*mp = m;
15653897Smckusick 		mp = &m->m_next;
15753897Smckusick 		totlen -= len;
15853897Smckusick 		if (cp == epkt)
15953897Smckusick 			cp = ifn->ifn_raddr + ifn->ifn_hlen;
16053897Smckusick 	}
16153897Smckusick 	return (top);
16253897Smckusick }
16353897Smckusick #endif /* NOTDEF */
16453897Smckusick 
16553897Smckusick /*
16653897Smckusick  * Map a chain of mbufs onto a network interface
16753897Smckusick  * in preparation for an i/o operation.
16853897Smckusick  * The argument chain of mbufs includes the local network header.
16953897Smckusick  */
if_wnewsput(ifn,m)17053897Smckusick if_wnewsput(ifn, m)
17153897Smckusick 	register struct ifnews *ifn;
17253897Smckusick 	register struct mbuf *m;
17353897Smckusick {
17453897Smckusick #ifdef CPU_DOUBLE
17553897Smckusick 	register struct mbuf_segment *ms;
17653897Smckusick 	register int n, i;
17753897Smckusick 
17853897Smckusick 	ifn->ifn_mbuf = m;
17953897Smckusick 	ms = (struct mbuf_segment *)ifn->ifn_waddr;
18053897Smckusick 	n = 0;
18153897Smckusick 	while (m) {
18253897Smckusick 		ms->ms_physaddr = kvtophys(mtod(m, caddr_t));
18353897Smckusick 		ms->ms_size = m->m_len;
18453897Smckusick 		if ((i = (ms->ms_physaddr & PGOFSET) + ms->ms_size) > NBPG) {
18553897Smckusick 			i -= NBPG;
18653897Smckusick 			ms->ms_size -= i;
18753897Smckusick 			ms++;
18853897Smckusick 			ms->ms_physaddr =
18953897Smckusick 			    kvtophys(mtod(m, caddr_t) + m->m_len - i);
19053897Smckusick 			ms->ms_size = i;
19153897Smckusick 		}
19253897Smckusick 		ms++;
19353897Smckusick 		n += m->m_len;
19453897Smckusick 		m = m->m_next;
19553897Smckusick 	}
19653897Smckusick 	ms->ms_physaddr = 0;
19753897Smckusick 	return (n);
19853897Smckusick #else /* CPU_DOUBLE */
19953897Smckusick 	register struct mbuf *mp;
20053897Smckusick 	register caddr_t cp;
20153897Smckusick 
20253897Smckusick 	cp = ifn->ifn_waddr;
20353897Smckusick 	while (m) {
20453897Smckusick #ifdef mips
20553897Smckusick 		bxcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
20653897Smckusick #else
20753897Smckusick 		bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
20853897Smckusick #endif
20953897Smckusick 		cp += m->m_len;
21053897Smckusick 		MFREE(m, mp);
21153897Smckusick 		m = mp;
21253897Smckusick 	}
21353897Smckusick 	return (cp - ifn->ifn_waddr);
21453897Smckusick #endif /* CPU_DOUBLE */
21553897Smckusick }
216