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 */
if_newsinit(ifn,hlen,nmr)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 *
if_rnewsget(ifn,totlen,off,ifp)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 = ⊤
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 */
if_wnewsput(ifn,m)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