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