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