if_patm_rx.c revision 175872
1139735Simp/*- 2244471Scognet * Copyright (c) 2003 3129198Scognet * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4129198Scognet * All rights reserved. 5129198Scognet * 6129198Scognet * Redistribution and use in source and binary forms, with or without 7129198Scognet * modification, are permitted provided that the following conditions 8129198Scognet * are met: 9129198Scognet * 1. Redistributions of source code must retain the above copyright 10129198Scognet * notice, this list of conditions and the following disclaimer. 11129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 12129198Scognet * notice, this list of conditions and the following disclaimer in the 13129198Scognet * documentation and/or other materials provided with the distribution. 14129198Scognet * 15129198Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17129198Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18129198Scognet * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19129198Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20129198Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21129198Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25129198Scognet * SUCH DAMAGE. 26129198Scognet * 27129198Scognet * Author: Hartmut Brandt <harti@freebsd.org> 28129198Scognet * 29129198Scognet * Driver for IDT77252 based cards like ProSum's. 30129198Scognet */ 31129198Scognet 32129198Scognet#include <sys/cdefs.h> 33129198Scognet__FBSDID("$FreeBSD: head/sys/dev/patm/if_patm_rx.c 175872 2008-02-01 19:36:27Z phk $"); 34129198Scognet 35129198Scognet#include "opt_inet.h" 36244471Scognet#include "opt_natm.h" 37244471Scognet 38244471Scognet#include <sys/types.h> 39244471Scognet#include <sys/param.h> 40244471Scognet#include <sys/systm.h> 41244471Scognet#include <sys/malloc.h> 42244471Scognet#include <sys/kernel.h> 43244471Scognet#include <sys/bus.h> 44244471Scognet#include <sys/errno.h> 45244471Scognet#include <sys/conf.h> 46244471Scognet#include <sys/module.h> 47244471Scognet#include <sys/lock.h> 48244471Scognet#include <sys/mutex.h> 49244471Scognet#include <sys/sysctl.h> 50244471Scognet#include <sys/queue.h> 51244471Scognet#include <sys/condvar.h> 52244471Scognet#include <sys/endian.h> 53129198Scognet#include <vm/uma.h> 54129198Scognet 55129198Scognet#include <sys/sockio.h> 56129198Scognet#include <sys/mbuf.h> 57129198Scognet#include <sys/socket.h> 58129198Scognet 59129198Scognet#include <net/if.h> 60244471Scognet#include <net/if_media.h> 61129198Scognet#include <net/if_atm.h> 62129198Scognet#include <net/route.h> 63129198Scognet#ifdef ENABLE_BPF 64246713Skib#include <net/bpf.h> 65129198Scognet#endif 66140310Scognet#include <netinet/in.h> 67146597Scognet#include <netinet/if_atm.h> 68166063Scognet 69246713Skib#include <machine/bus.h> 70129198Scognet#include <machine/resource.h> 71244471Scognet#include <sys/bus.h> 72129198Scognet#include <sys/rman.h> 73244471Scognet#include <sys/mbpool.h> 74244471Scognet 75129198Scognet#include <dev/utopia/utopia.h> 76129198Scognet#include <dev/patm/idt77252reg.h> 77129198Scognet#include <dev/patm/if_patmvar.h> 78129198Scognet 79129198Scognetstatic void *patm_rcv_handle(struct patm_softc *sc, u_int handle); 80129198Scognetstatic void patm_rcv_free(struct patm_softc *, void *, u_int handle); 81166063Scognetstatic struct mbuf *patm_rcv_mbuf(struct patm_softc *, void *, u_int, int); 82129198Scognet 83166063Scognetstatic __inline void 84166063Scognetrct_write(struct patm_softc *sc, u_int cid, u_int w, u_int val) 85166063Scognet{ 86166063Scognet patm_sram_write(sc, sc->mmap->rct + cid * IDT_RCT_ENTRY_SIZE + w, val); 87166063Scognet} 88166063Scognetstatic __inline u_int 89129198Scognetrct_read(struct patm_softc *sc, u_int cid, u_int w) 90129198Scognet{ 91129198Scognet return (patm_sram_read(sc, sc->mmap->rct + 92232356Sjhb cid * IDT_RCT_ENTRY_SIZE + w)); 93129198Scognet} 94129198Scognet 95129198Scognet/* check if we can open this one */ 96129198Scognetint 97129198Scognetpatm_rx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc) 98129198Scognet{ 99129198Scognet return (0); 100129198Scognet} 101129198Scognet 102129198Scognet/* 103129198Scognet * open the VCC 104129198Scognet */ 105129198Scognetvoid 106129198Scognetpatm_rx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc) 107129198Scognet{ 108129198Scognet uint32_t w1 = IDT_RCT_OPEN; 109129198Scognet 110129198Scognet patm_debug(sc, VCC, "%u.%u RX opening", vcc->vcc.vpi, vcc->vcc.vci); 111129198Scognet 112129198Scognet switch (vcc->vcc.aal) { 113166063Scognet case ATMIO_AAL_0: 114244471Scognet w1 |= IDT_RCT_AAL0 | IDT_RCT_FBP2 | IDT_RCT_RCI; 115244471Scognet break; 116244471Scognet case ATMIO_AAL_34: 117244471Scognet w1 |= IDT_RCT_AAL34; 118244471Scognet break; 119244471Scognet case ATMIO_AAL_5: 120244471Scognet w1 |= IDT_RCT_AAL5; 121129198Scognet break; 122129198Scognet case ATMIO_AAL_RAW: 123166063Scognet w1 |= IDT_RCT_AALRAW | IDT_RCT_RCI; 124166063Scognet break; 125166063Scognet } 126166063Scognet 127166063Scognet if (vcc->cid != 0) 128246713Skib patm_sram_write4(sc, sc->mmap->rct + vcc->cid * 129166063Scognet IDT_RCT_ENTRY_SIZE, w1, 0, 0, 0xffffffff); 130166063Scognet else { 131166063Scognet /* switch the interface into promiscuous mode */ 132166063Scognet patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) | 133246713Skib IDT_CFG_ICAPT | IDT_CFG_VPECA); 134246713Skib } 135246713Skib 136246713Skib vcc->vflags |= PATM_VCC_RX_OPEN; 137246713Skib} 138246713Skib 139166063Scognet/* close the given vcc for transmission */ 140166063Scognetvoid 141166063Scognetpatm_rx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc) 142166063Scognet{ 143166063Scognet u_int w1; 144166063Scognet 145166063Scognet patm_debug(sc, VCC, "%u.%u RX closing", vcc->vcc.vpi, vcc->vcc.vci); 146166063Scognet 147166063Scognet if (vcc->cid == 0) { 148166063Scognet /* switch off promiscuous mode */ 149166063Scognet patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) & 150188403Scognet ~(IDT_CFG_ICAPT | IDT_CFG_VPECA)); 151166063Scognet vcc->vflags &= ~PATM_VCC_RX_OPEN; 152166063Scognet return; 153166063Scognet } 154166063Scognet 155166063Scognet /* close the connection but keep state */ 156166063Scognet w1 = rct_read(sc, vcc->cid, 0); 157166063Scognet w1 &= ~IDT_RCT_OPEN; 158166063Scognet rct_write(sc, vcc->cid, 0, w1); 159166063Scognet 160166063Scognet /* minimum idle count */ 161166063Scognet w1 = (w1 & ~IDT_RCT_IACT_CNT_MASK) | (1 << IDT_RCT_IACT_CNT_SHIFT); 162166063Scognet rct_write(sc, vcc->cid, 0, w1); 163166063Scognet 164227309Sed /* initialize scan */ 165166063Scognet patm_nor_write(sc, IDT_NOR_IRCP, vcc->cid); 166166063Scognet 167166063Scognet vcc->vflags &= ~PATM_VCC_RX_OPEN; 168246713Skib vcc->vflags |= PATM_VCC_RX_CLOSING; 169244471Scognet 170246713Skib /* 171129198Scognet * check the RSQ 172166063Scognet * This is a hack. The problem is, that although an entry is written 173166063Scognet * to the RSQ, no interrupt is generated. Also we must wait 1 cell 174166063Scognet * time for the SAR to process the scan of our connection. 175135644Scognet */ 176246713Skib DELAY(1); 177135644Scognet patm_intr_rsq(sc); 178166063Scognet} 179166063Scognet 180166063Scognet/* transmission side finally closed */ 181246713Skibvoid 182246713Skibpatm_rx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc) 183129198Scognet{ 184129198Scognet patm_debug(sc, VCC, "%u.%u RX finally closed", 185166063Scognet vcc->vcc.vpi, vcc->vcc.vci); 186166063Scognet} 187166063Scognet 188146597Scognet/* 189146597Scognet * Handle the given receive status queue entry 190146597Scognet */ 191146597Scognetvoid 192166063Scognetpatm_rx(struct patm_softc *sc, struct idt_rsqe *rsqe) 193166063Scognet{ 194166063Scognet struct mbuf *m; 195166063Scognet void *buf; 196166063Scognet u_int stat, cid, w, cells, len, h; 197166063Scognet struct patm_vcc *vcc; 198246713Skib struct atm_pseudohdr aph; 199246713Skib u_char *trail; 200166063Scognet 201166063Scognet cid = le32toh(rsqe->cid); 202166063Scognet stat = le32toh(rsqe->stat); 203166063Scognet h = le32toh(rsqe->handle); 204166063Scognet 205244473Scognet cid = PATM_CID(sc, IDT_RSQE_VPI(cid), IDT_RSQE_VCI(cid)); 206244473Scognet vcc = sc->vccs[cid]; 207244473Scognet 208244473Scognet if (IDT_RSQE_TYPE(stat) == IDT_RSQE_IDLE) { 209244471Scognet /* connection has gone idle */ 210244471Scognet if (stat & IDT_RSQE_BUF) 211244471Scognet patm_rcv_free(sc, patm_rcv_handle(sc, h), h); 212244471Scognet 213244471Scognet w = rct_read(sc, cid, 0); 214244471Scognet if (w != 0 && !(w & IDT_RCT_OPEN)) 215166063Scognet rct_write(sc, cid, 0, 0); 216244471Scognet if (vcc != NULL && (vcc->vflags & PATM_VCC_RX_CLOSING)) { 217244471Scognet patm_debug(sc, VCC, "%u.%u RX closed", vcc->vcc.vpi, 218244471Scognet vcc->vcc.vci); 219244471Scognet vcc->vflags &= ~PATM_VCC_RX_CLOSING; 220244471Scognet if (vcc->vcc.flags & ATMIO_FLAG_ASYNC) { 221244471Scognet patm_rx_vcc_closed(sc, vcc); 222244471Scognet if (!(vcc->vflags & PATM_VCC_OPEN)) 223244471Scognet patm_vcc_closed(sc, vcc); 224244471Scognet } else 225244471Scognet cv_signal(&sc->vcc_cv); 226244471Scognet } 227244471Scognet return; 228244471Scognet } 229244471Scognet 230244471Scognet buf = patm_rcv_handle(sc, h); 231244471Scognet 232244471Scognet if (vcc == NULL || (vcc->vflags & PATM_VCC_RX_OPEN) == 0) { 233244471Scognet patm_rcv_free(sc, buf, h); 234244471Scognet return; 235244471Scognet } 236244471Scognet 237244471Scognet cells = IDT_RSQE_CNT(stat); 238244471Scognet KASSERT(cells > 0, ("zero cell count")); 239244471Scognet 240244471Scognet if (vcc->vcc.aal == ATMIO_AAL_0) { 241244471Scognet /* deliver this packet as it is */ 242244471Scognet if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL) 243244471Scognet return; 244244471Scognet 245244471Scognet m->m_len = cells * 48; 246244471Scognet m->m_pkthdr.len = m->m_len; 247244471Scognet m->m_pkthdr.rcvif = sc->ifp; 248244471Scognet 249244471Scognet } else if (vcc->vcc.aal == ATMIO_AAL_34) { 250244471Scognet /* XXX AAL3/4 */ 251244471Scognet patm_rcv_free(sc, buf, h); 252244471Scognet return; 253244471Scognet 254244471Scognet } else if (vcc->vcc.aal == ATMIO_AAL_5) { 255244471Scognet if (stat & IDT_RSQE_CRC) { 256244471Scognet sc->ifp->if_ierrors++; 257244471Scognet if (vcc->chain != NULL) { 258244471Scognet m_freem(vcc->chain); 259244471Scognet vcc->chain = vcc->last = NULL; 260244471Scognet } 261244471Scognet return; 262244471Scognet } 263244471Scognet 264244471Scognet /* append to current chain */ 265244471Scognet if (vcc->chain == NULL) { 266244471Scognet if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL) 267244471Scognet return; 268244471Scognet m->m_len = cells * 48; 269244471Scognet m->m_pkthdr.len = m->m_len; 270244471Scognet m->m_pkthdr.rcvif = sc->ifp; 271244471Scognet vcc->chain = vcc->last = m; 272244471Scognet } else { 273244471Scognet if ((m = patm_rcv_mbuf(sc, buf, h, 0)) == NULL) 274244471Scognet return; 275244471Scognet m->m_len = cells * 48; 276244471Scognet vcc->last->m_next = m; 277244471Scognet vcc->last = m; 278244471Scognet vcc->chain->m_pkthdr.len += m->m_len; 279244471Scognet } 280244471Scognet 281244471Scognet if (!(stat & IDT_RSQE_EPDU)) 282244471Scognet return; 283244471Scognet 284244471Scognet trail = mtod(m, u_char *) + m->m_len - 6; 285244473Scognet len = (trail[0] << 8) + trail[1]; 286244473Scognet 287244473Scognet if ((u_int)vcc->chain->m_pkthdr.len < len + 8) { 288244473Scognet patm_printf(sc, "%s: bad aal5 lengths %u %u\n", 289244471Scognet __func__, (u_int)m->m_pkthdr.len, len); 290244471Scognet m_freem(vcc->chain); 291166063Scognet vcc->chain = vcc->last = NULL; 292166063Scognet return; 293166063Scognet } 294166063Scognet m->m_len -= vcc->chain->m_pkthdr.len - len; 295166063Scognet KASSERT(m->m_len >= 0, ("bad last mbuf")); 296166063Scognet 297166063Scognet m = vcc->chain; 298166063Scognet vcc->chain = vcc->last = NULL; 299166063Scognet m->m_pkthdr.len = len; 300166063Scognet } else 301166063Scognet panic("bad aal"); 302166063Scognet 303166063Scognet#if 0 304166063Scognet { 305166063Scognet u_int i; 306166063Scognet 307166063Scognet for (i = 0; i < m->m_len; i++) { 308166063Scognet printf("%02x ", mtod(m, u_char *)[i]); 309166063Scognet } 310166063Scognet printf("\n"); 311166063Scognet } 312166063Scognet#endif 313166063Scognet 314166063Scognet sc->ifp->if_ipackets++; 315166063Scognet /* this is in if_atmsubr.c */ 316166063Scognet /* sc->ifp->if_ibytes += m->m_pkthdr.len; */ 317129198Scognet 318244471Scognet vcc->ibytes += m->m_pkthdr.len; 319244471Scognet vcc->ipackets++; 320244471Scognet 321244471Scognet ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff; 322244471Scognet ATM_PH_VPI(&aph) = IDT_RSQE_VPI(cid); 323244471Scognet ATM_PH_SETVCI(&aph, IDT_RSQE_VCI(cid)); 324244471Scognet 325244471Scognet#ifdef ENABLE_BPF 326244471Scognet if (!(vcc->vcc.flags & ATMIO_FLAG_NG) && 327244471Scognet (vcc->vcc.aal == ATMIO_AAL_5) && 328129198Scognet (vcc->vcc.flags & ATM_PH_LLCSNAP)) 329137758Scognet BPF_MTAP(sc->ifp, m); 330166063Scognet#endif 331166063Scognet 332166063Scognet atm_input(sc->ifp, &aph, m, vcc->rxhand); 333244471Scognet} 334244471Scognet 335244471Scognet/* 336244471Scognet * Get the buffer for a receive handle. This is either an mbuf for 337166063Scognet * a large handle or a pool buffer for the others. 338166063Scognet */ 339236991Simpstatic void * 340166063Scognetpatm_rcv_handle(struct patm_softc *sc, u_int handle) 341166063Scognet{ 342166063Scognet void *buf; 343166063Scognet u_int c; 344166063Scognet 345166063Scognet if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE) { 346129198Scognet struct lmbuf *b; 347129198Scognet 348129198Scognet c = handle & MBUF_HMASK; 349129198Scognet b = &sc->lbufs[c]; 350129198Scognet 351129198Scognet buf = b->m; 352129198Scognet b->m = NULL; 353129198Scognet 354129198Scognet bus_dmamap_sync(sc->lbuf_tag, b->map, BUS_DMASYNC_POSTREAD); 355129198Scognet patm_lbuf_free(sc, b); 356129198Scognet 357129198Scognet } else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE) { 358129198Scognet mbp_sync(sc->vbuf_pool, handle, 359129198Scognet 0, VMBUF_SIZE, BUS_DMASYNC_POSTREAD); 360129198Scognet buf = mbp_get(sc->vbuf_pool, handle); 361129198Scognet 362129198Scognet } else { 363129198Scognet mbp_sync(sc->sbuf_pool, handle, 364129198Scognet 0, SMBUF_SIZE, BUS_DMASYNC_POSTREAD); 365129198Scognet buf = mbp_get(sc->sbuf_pool, handle); 366129198Scognet } 367129198Scognet 368129198Scognet return (buf); 369129198Scognet} 370129198Scognet 371129198Scognet/* 372129198Scognet * Free a buffer. 373129198Scognet */ 374129198Scognetstatic void 375129198Scognetpatm_rcv_free(struct patm_softc *sc, void *p, u_int handle) 376129198Scognet{ 377129198Scognet if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE) 378129198Scognet m_free((struct mbuf *)p); 379129198Scognet 380129198Scognet else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE) 381129198Scognet mbp_free(sc->vbuf_pool, p); 382129198Scognet 383129198Scognet else 384129198Scognet mbp_free(sc->sbuf_pool, p); 385129198Scognet} 386129198Scognet 387129198Scognet/* 388129198Scognet * Make an mbuf around the buffer 389129198Scognet */ 390129198Scognetstatic struct mbuf * 391129198Scognetpatm_rcv_mbuf(struct patm_softc *sc, void *buf, u_int h, int hdr) 392129198Scognet{ 393129198Scognet struct mbuf *m; 394129198Scognet 395129198Scognet if ((h & ~MBUF_HMASK) == MBUF_LHANDLE) 396129198Scognet return ((struct mbuf *)buf); 397129198Scognet 398129198Scognet if (hdr) 399129198Scognet MGETHDR(m, M_DONTWAIT, MT_DATA); 400129198Scognet else 401129198Scognet MGET(m, M_DONTWAIT, MT_DATA); 402129198Scognet if (m == NULL) { 403129198Scognet patm_rcv_free(sc, buf, h); 404135644Scognet return (NULL); 405135644Scognet } 406129198Scognet 407129198Scognet if ((h & ~MBUF_HMASK) == MBUF_VHANDLE) { 408232356Sjhb MEXTADD(m, (caddr_t)buf, VMBUF_SIZE, mbp_ext_free, 409129198Scognet buf, sc->vbuf_pool, M_PKTHDR, EXT_NET_DRV); 410129198Scognet m->m_data += VMBUF_OFFSET; 411129198Scognet } else { 412129198Scognet MEXTADD(m, (caddr_t)buf, SMBUF_SIZE, mbp_ext_free, 413129198Scognet buf, sc->sbuf_pool, M_PKTHDR, EXT_NET_DRV); 414129198Scognet m->m_data += SMBUF_OFFSET; 415129198Scognet } 416129198Scognet 417129198Scognet if (!(m->m_flags & M_EXT)) { 418166063Scognet patm_rcv_free(sc, buf, h); 419166063Scognet m_free(m); 420129198Scognet return (NULL); 421129198Scognet } 422140313Scognet return (m); 423143294Smux} 424143284Smux 425129198Scognet/* 426140313Scognet * Process the raw cell at the given address. 427129198Scognet */ 428129198Scognetvoid 429244471Scognetpatm_rx_raw(struct patm_softc *sc, u_char *cell) 430129198Scognet{ 431129198Scognet u_int vpi, vci, cid; 432129198Scognet struct patm_vcc *vcc; 433129198Scognet struct mbuf *m; 434129198Scognet u_char *dst; 435129198Scognet struct timespec ts; 436129198Scognet struct atm_pseudohdr aph; 437129198Scognet uint64_t cts; 438129198Scognet 439129198Scognet sc->stats.raw_cells++; 440129198Scognet 441129198Scognet /* 442135644Scognet * For some non-appearant reason the cell header 443129198Scognet * is in the wrong endian. 444129198Scognet */ 445129198Scognet *(uint32_t *)cell = bswap32(*(uint32_t *)cell); 446129198Scognet 447129198Scognet vpi = ((cell[0] & 0xf) << 4) | ((cell[1] & 0xf0) >> 4); 448129198Scognet vci = ((cell[1] & 0xf) << 12) | (cell[2] << 4) | ((cell[3] & 0xf0) >> 4); 449129198Scognet cid = PATM_CID(sc, vpi, vci); 450244471Scognet 451244471Scognet vcc = sc->vccs[cid]; 452244471Scognet if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN) || 453244471Scognet vcc->vcc.aal != ATMIO_AAL_RAW) { 454244471Scognet vcc = sc->vccs[0]; 455244471Scognet if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN)) { 456244471Scognet sc->stats.raw_no_vcc++; 457244471Scognet return; 458244471Scognet } 459244471Scognet } 460244471Scognet 461244471Scognet MGETHDR(m, M_DONTWAIT, MT_DATA); 462244471Scognet if (m == NULL) { 463129198Scognet sc->stats.raw_no_buf++; 464129198Scognet return; 465129198Scognet } 466232356Sjhb m->m_pkthdr.rcvif = sc->ifp; 467232356Sjhb 468134934Sscottl switch (vcc->vflags & PATM_RAW_FORMAT) { 469134934Sscottl 470134934Sscottl default: 471232356Sjhb case PATM_RAW_CELL: 472134934Sscottl m->m_len = m->m_pkthdr.len = 53; 473166063Scognet MH_ALIGN(m, 53); 474166063Scognet dst = mtod(m, u_char *); 475166063Scognet *dst++ = *cell++; 476129198Scognet *dst++ = *cell++; 477129198Scognet *dst++ = *cell++; 478129198Scognet *dst++ = *cell++; 479129198Scognet *dst++ = 0; /* HEC */ 480129198Scognet bcopy(cell + 12, dst, 48); 481129198Scognet break; 482129198Scognet 483129198Scognet case PATM_RAW_NOHEC: 484129198Scognet m->m_len = m->m_pkthdr.len = 52; 485129198Scognet MH_ALIGN(m, 52); 486129198Scognet dst = mtod(m, u_char *); 487129198Scognet *dst++ = *cell++; 488166063Scognet *dst++ = *cell++; 489166063Scognet *dst++ = *cell++; 490166063Scognet *dst++ = *cell++; 491129198Scognet bcopy(cell + 12, dst, 48); 492166063Scognet break; 493166063Scognet 494166063Scognet case PATM_RAW_CS: 495166063Scognet m->m_len = m->m_pkthdr.len = 64; 496166063Scognet MH_ALIGN(m, 64); 497166063Scognet dst = mtod(m, u_char *); 498166063Scognet *dst++ = *cell++; 499166063Scognet *dst++ = *cell++; 500166063Scognet *dst++ = *cell++; 501166063Scognet *dst++ = *cell++; 502166063Scognet *dst++ = 0; /* HEC */ 503166063Scognet *dst++ = 0; /* flags */ 504166063Scognet *dst++ = 0; /* reserved */ 505166063Scognet *dst++ = 0; /* reserved */ 506166063Scognet nanotime(&ts); 507166063Scognet cts = ts.tv_sec * 1000000000ULL + ts.tv_nsec; 508166063Scognet bcopy(dst, &cts, 8); 509166063Scognet bcopy(cell + 12, dst + 8, 48); 510166063Scognet break; 511166063Scognet } 512166063Scognet 513166063Scognet sc->ifp->if_ipackets++; 514166063Scognet /* this is in if_atmsubr.c */ 515170502Scognet /* sc->ifp->if_ibytes += m->m_pkthdr.len; */ 516170502Scognet 517166063Scognet vcc->ibytes += m->m_pkthdr.len; 518166063Scognet vcc->ipackets++; 519166063Scognet 520166063Scognet ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff; 521143294Smux ATM_PH_VPI(&aph) = vcc->vcc.vpi; 522143284Smux ATM_PH_SETVCI(&aph, vcc->vcc.vci); 523140313Scognet 524129198Scognet atm_input(sc->ifp, &aph, m, vcc->rxhand); 525129198Scognet} 526129198Scognet