xref: /original-bsd/sys/news3400/if/if_news.c (revision 3b43aa51)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
7  *
8  * %sccs.include.redist.c%
9  *
10  * from: $Hdr: if_news.c,v 4.300 91/06/09 06:26:01 root Rel41 $ SONY
11  *
12  *	@(#)if_news.c	7.4 (Berkeley) 01/20/93
13  */
14 
15 #include <sys/types.h>
16 #include <machine/fix_machine_type.h>
17 #include <machine/pte.h>
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/mbuf.h>
22 #include <sys/map.h>
23 #include <sys/buf.h>
24 #include <sys/socket.h>
25 #include <sys/proc.h>
26 #include <sys/user.h>
27 
28 #include <net/if.h>
29 #include <news3400/if/if_news.h>
30 #include <machine/cpu.h>
31 
32 #if MCLBYTES == CLBYTES && defined(CPU_DOUBLE)
33 #define	USE_CLUSTER
34 #endif
35 
36 /*
37  * Routines supporting NEWS network interfaces.
38  */
39 #define btomcl(x)       (((x) + MCLBYTES - 1) >> MCLSHIFT)
40 
41 /*
42  * Init NEWS for interface on uban whose headers of size hlen are to
43  * end on a page boundary.  We also allocate page frames in the mbuffer pool
44  * for these pages.
45  */
46 if_newsinit(ifn, hlen, nmr)
47 	register struct ifnews *ifn;
48 	int hlen, nmr;
49 {
50 #ifdef USE_CLUSTER
51 	register caddr_t cp;
52 	int ncl;
53 
54 	if (ifn->ifn_raddr)
55 		return (1);
56 	ncl = nmr;
57 	cp = malloc(btomcl(ctob(2 * ncl)), M_DEVBUF, M_NOWAIT); /*XXX*/
58 	if (cp == 0)
59 		return (0);
60 	ifn->ifn_raddr = cp + 4 - (hlen & 03);
61 	ifn->ifn_waddr = cp + ncl * MCLBYTES;
62 #endif /* USE_CLUSTER */
63 	ifn->ifn_hlen = hlen;
64 	return (1);
65 }
66 
67 /*
68  * Pull read data off a interface.
69  * Len is length of data, with local net header stripped.
70  * Off is non-zero if a trailer protocol was used, and
71  * gives the offset of the trailer information.
72  * We copy the trailer information and then all the normal
73  * data into mbufs.  When large sized units are present
74  * on the interface on cluster boundaries we can get them more
75  * easily by remapping, and take advantage of this here.
76  */
77 #ifdef NOTDEF /* use m_devget */
78 struct mbuf *
79 if_rnewsget(ifn, totlen, off, ifp)
80 	register struct ifnews *ifn;
81 	register int totlen, off;
82 	struct ifnet *ifp;
83 {
84 	register struct mbuf **mp, *m;
85 	struct mbuf *top;
86 	register int len;
87 	register caddr_t cp = ifn->ifn_raddr + ifn->ifn_hlen;
88 	caddr_t epkt = cp + totlen;
89 
90 #ifdef USE_CLUSTER
91 	if (totlen >= MHLEN && off == 0) {
92 		MGETHDR(m, M_DONTWAIT, MT_DATA);
93 		if (m == 0)
94 			return (0);
95 		m->m_pkthdr.rcvif = ifp;
96 		m->m_pkthdr.len = totlen;
97 		MCLGET(m, M_DONTWAIT);
98 		if (m->m_len != MCLBYTES) {
99 			struct mbuf *n;
100 
101 			MFREE(m, n);
102 			goto noncluster;
103 		}
104 		pageswap(cp - ifn->ifn_hlen, mtod(m, caddr_t),
105 		    totlen + ifn->ifn_hlen);
106 		m->m_len = totlen;
107 		m->m_data += ifn->ifn_hlen + 4 - (ifn->ifn_hlen & 03);
108 		return (m);
109 	}
110 noncluster:
111 #endif /* USE_CLUSTER */
112 	top = 0;
113 	mp = &top;
114 	/*
115 	 * Skip the trailer header (type and trailer length).
116 	 */
117 	if (off) {
118 		off += 2 * sizeof(u_short);
119 		totlen -= 2 * sizeof(u_short);
120 		cp += off;
121 	}
122 	MGETHDR(m, M_DONTWAIT, MT_DATA);
123 	if (m == 0)
124 		return ((struct mbuf *)NULL);
125 	m->m_pkthdr.rcvif = ifp;
126 	m->m_pkthdr.len = totlen;
127 	m->m_len = MHLEN;
128 
129 	while (totlen > 0) {
130 		if (top) {
131 			MGET(m, M_DONTWAIT, MT_DATA);
132 			if (m == 0) {
133 				m_freem(top);
134 				return(0);
135 			}
136 			m->m_len = MLEN;
137 		}
138 
139 		if (totlen >= MINCLSIZE)
140 			MCLGET(m, M_DONTWAIT);
141 		if (m->m_flags & M_EXT)
142 			m->m_len = min(totlen, MCLBYTES);
143 		else if (totlen < m->m_len) {
144 			/*
145 			 * Place initial small packet/header at end of mbuf.
146 			 */
147 			if (top == 0 && totlen + max_linkhdr <= m->m_len)
148 				m->m_data += max_linkhdr;
149 			m->m_len = totlen;
150 		}
151 		len = m->m_len;
152 copy:
153 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
154 		cp += len;
155 nocopy:
156 		*mp = m;
157 		mp = &m->m_next;
158 		totlen -= len;
159 		if (cp == epkt)
160 			cp = ifn->ifn_raddr + ifn->ifn_hlen;
161 	}
162 	return (top);
163 }
164 #endif /* NOTDEF */
165 
166 /*
167  * Map a chain of mbufs onto a network interface
168  * in preparation for an i/o operation.
169  * The argument chain of mbufs includes the local network header.
170  */
171 if_wnewsput(ifn, m)
172 	register struct ifnews *ifn;
173 	register struct mbuf *m;
174 {
175 #ifdef CPU_DOUBLE
176 	register struct mbuf_segment *ms;
177 	register int n, i;
178 
179 	ifn->ifn_mbuf = m;
180 	ms = (struct mbuf_segment *)ifn->ifn_waddr;
181 	n = 0;
182 	while (m) {
183 		ms->ms_physaddr = kvtophys(mtod(m, caddr_t));
184 		ms->ms_size = m->m_len;
185 		if ((i = (ms->ms_physaddr & PGOFSET) + ms->ms_size) > NBPG) {
186 			i -= NBPG;
187 			ms->ms_size -= i;
188 			ms++;
189 			ms->ms_physaddr =
190 			    kvtophys(mtod(m, caddr_t) + m->m_len - i);
191 			ms->ms_size = i;
192 		}
193 		ms++;
194 		n += m->m_len;
195 		m = m->m_next;
196 	}
197 	ms->ms_physaddr = 0;
198 	return (n);
199 #else /* CPU_DOUBLE */
200 	register struct mbuf *mp;
201 	register caddr_t cp;
202 
203 	cp = ifn->ifn_waddr;
204 	while (m) {
205 #ifdef mips
206 		bxcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
207 #else
208 		bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
209 #endif
210 		cp += m->m_len;
211 		MFREE(m, mp);
212 		m = mp;
213 	}
214 	return (cp - ifn->ifn_waddr);
215 #endif /* CPU_DOUBLE */
216 }
217