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.2 (Berkeley) 07/28/92 13 */ 14 15 #include "types.h" 16 #include "../include/fix_machine_type.h" 17 #include "../include/pte.h" 18 19 #include "param.h" 20 #include "systm.h" 21 #include "mbuf.h" 22 #include "map.h" 23 #include "buf.h" 24 #include "socket.h" 25 #include "proc.h" 26 #include "user.h" 27 28 #include "../net/if.h" 29 #include "../if/if_news.h" 30 #include "../include/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 = ⊤ 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