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 = ⊤
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