if_patm_rx.c revision 243857
1139749Simp/*-
2117632Sharti * Copyright (c) 2003
3117632Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4117632Sharti * 	All rights reserved.
5117632Sharti *
6117632Sharti * Redistribution and use in source and binary forms, with or without
7117632Sharti * modification, are permitted provided that the following conditions
8117632Sharti * are met:
9117632Sharti * 1. Redistributions of source code must retain the above copyright
10117632Sharti *    notice, this list of conditions and the following disclaimer.
11117632Sharti * 2. Redistributions in binary form must reproduce the above copyright
12117632Sharti *    notice, this list of conditions and the following disclaimer in the
13117632Sharti *    documentation and/or other materials provided with the distribution.
14117632Sharti *
15117632Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16117632Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17117632Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18117632Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19117632Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20117632Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21117632Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22117632Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23117632Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24117632Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25117632Sharti * SUCH DAMAGE.
26117632Sharti *
27117632Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28117632Sharti *
29117632Sharti * Driver for IDT77252 based cards like ProSum's.
30117632Sharti */
31119418Sobrien
32117632Sharti#include <sys/cdefs.h>
33117632Sharti__FBSDID("$FreeBSD: head/sys/dev/patm/if_patm_rx.c 243857 2012-12-04 09:32:43Z glebius $");
34117632Sharti
35117632Sharti#include "opt_inet.h"
36117632Sharti#include "opt_natm.h"
37117632Sharti
38117632Sharti#include <sys/types.h>
39117632Sharti#include <sys/param.h>
40117632Sharti#include <sys/systm.h>
41117632Sharti#include <sys/malloc.h>
42117632Sharti#include <sys/kernel.h>
43117632Sharti#include <sys/bus.h>
44117632Sharti#include <sys/errno.h>
45117632Sharti#include <sys/conf.h>
46117632Sharti#include <sys/module.h>
47117632Sharti#include <sys/lock.h>
48117632Sharti#include <sys/mutex.h>
49117632Sharti#include <sys/sysctl.h>
50117632Sharti#include <sys/queue.h>
51117632Sharti#include <sys/condvar.h>
52117632Sharti#include <sys/endian.h>
53117632Sharti#include <vm/uma.h>
54117632Sharti
55117632Sharti#include <sys/sockio.h>
56117632Sharti#include <sys/mbuf.h>
57117632Sharti#include <sys/socket.h>
58117632Sharti
59117632Sharti#include <net/if.h>
60117632Sharti#include <net/if_media.h>
61117632Sharti#include <net/if_atm.h>
62117632Sharti#include <net/route.h>
63117632Sharti#ifdef ENABLE_BPF
64117632Sharti#include <net/bpf.h>
65117632Sharti#endif
66117632Sharti#include <netinet/in.h>
67117632Sharti#include <netinet/if_atm.h>
68117632Sharti
69117632Sharti#include <machine/bus.h>
70117632Sharti#include <machine/resource.h>
71117632Sharti#include <sys/bus.h>
72117632Sharti#include <sys/rman.h>
73117632Sharti#include <sys/mbpool.h>
74117632Sharti
75117632Sharti#include <dev/utopia/utopia.h>
76117632Sharti#include <dev/patm/idt77252reg.h>
77117632Sharti#include <dev/patm/if_patmvar.h>
78117632Sharti
79117632Shartistatic void *patm_rcv_handle(struct patm_softc *sc, u_int handle);
80117632Shartistatic void patm_rcv_free(struct patm_softc *, void *, u_int handle);
81117632Shartistatic struct mbuf *patm_rcv_mbuf(struct patm_softc *, void *, u_int, int);
82117632Sharti
83117632Shartistatic __inline void
84117632Shartirct_write(struct patm_softc *sc, u_int cid, u_int w, u_int val)
85117632Sharti{
86117632Sharti	patm_sram_write(sc, sc->mmap->rct + cid * IDT_RCT_ENTRY_SIZE + w, val);
87117632Sharti}
88117632Shartistatic __inline u_int
89117632Shartirct_read(struct patm_softc *sc, u_int cid, u_int w)
90117632Sharti{
91117632Sharti	return (patm_sram_read(sc, sc->mmap->rct +
92117632Sharti	    cid * IDT_RCT_ENTRY_SIZE + w));
93117632Sharti}
94117632Sharti
95117632Sharti/* check if we can open this one */
96117632Shartiint
97117632Shartipatm_rx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc)
98117632Sharti{
99117632Sharti	return (0);
100117632Sharti}
101117632Sharti
102117632Sharti/*
103117632Sharti * open the VCC
104117632Sharti */
105117632Shartivoid
106117632Shartipatm_rx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc)
107117632Sharti{
108117632Sharti	uint32_t w1 = IDT_RCT_OPEN;
109117632Sharti
110117632Sharti	patm_debug(sc, VCC, "%u.%u RX opening", vcc->vcc.vpi, vcc->vcc.vci);
111117632Sharti
112117632Sharti	switch (vcc->vcc.aal) {
113117632Sharti	  case ATMIO_AAL_0:
114117632Sharti		w1 |= IDT_RCT_AAL0 | IDT_RCT_FBP2 | IDT_RCT_RCI;
115117632Sharti		break;
116117632Sharti	  case ATMIO_AAL_34:
117117632Sharti		w1 |= IDT_RCT_AAL34;
118117632Sharti		break;
119117632Sharti	  case ATMIO_AAL_5:
120117632Sharti		w1 |= IDT_RCT_AAL5;
121117632Sharti		break;
122117632Sharti	  case ATMIO_AAL_RAW:
123117632Sharti		w1 |= IDT_RCT_AALRAW | IDT_RCT_RCI;
124117632Sharti		break;
125117632Sharti	}
126117632Sharti
127117632Sharti	if (vcc->cid != 0)
128118061Sharti		patm_sram_write4(sc, sc->mmap->rct + vcc->cid *
129118061Sharti		    IDT_RCT_ENTRY_SIZE, w1, 0, 0, 0xffffffff);
130117632Sharti	else {
131117632Sharti		/* switch the interface into promiscuous mode */
132117632Sharti		patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) |
133117632Sharti		    IDT_CFG_ICAPT | IDT_CFG_VPECA);
134117632Sharti	}
135117632Sharti
136117632Sharti	vcc->vflags |= PATM_VCC_RX_OPEN;
137117632Sharti}
138117632Sharti
139117632Sharti/* close the given vcc for transmission */
140117632Shartivoid
141117632Shartipatm_rx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc)
142117632Sharti{
143117632Sharti	u_int w1;
144117632Sharti
145117632Sharti	patm_debug(sc, VCC, "%u.%u RX closing", vcc->vcc.vpi, vcc->vcc.vci);
146117632Sharti
147117632Sharti	if (vcc->cid == 0) {
148117632Sharti		/* switch off promiscuous mode */
149117632Sharti		patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) &
150117632Sharti		    ~(IDT_CFG_ICAPT | IDT_CFG_VPECA));
151117632Sharti		vcc->vflags &= ~PATM_VCC_RX_OPEN;
152117632Sharti		return;
153117632Sharti	}
154117632Sharti
155117632Sharti	/* close the connection but keep state */
156117632Sharti	w1 = rct_read(sc, vcc->cid, 0);
157117632Sharti	w1 &= ~IDT_RCT_OPEN;
158117632Sharti	rct_write(sc, vcc->cid, 0, w1);
159117632Sharti
160117632Sharti	/* minimum idle count */
161117632Sharti	w1 = (w1 & ~IDT_RCT_IACT_CNT_MASK) | (1 << IDT_RCT_IACT_CNT_SHIFT);
162117632Sharti	rct_write(sc, vcc->cid, 0, w1);
163117632Sharti
164117632Sharti	/* initialize scan */
165117632Sharti	patm_nor_write(sc, IDT_NOR_IRCP, vcc->cid);
166117632Sharti
167117632Sharti	vcc->vflags &= ~PATM_VCC_RX_OPEN;
168117632Sharti	vcc->vflags |= PATM_VCC_RX_CLOSING;
169117632Sharti
170117632Sharti	/*
171117632Sharti	 * check the RSQ
172117632Sharti	 * This is a hack. The problem is, that although an entry is written
173117632Sharti	 * to the RSQ, no interrupt is generated. Also we must wait 1 cell
174117632Sharti	 * time for the SAR to process the scan of our connection.
175117632Sharti	 */
176117632Sharti	DELAY(1);
177117632Sharti	patm_intr_rsq(sc);
178117632Sharti}
179117632Sharti
180117632Sharti/* transmission side finally closed */
181117632Shartivoid
182117632Shartipatm_rx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
183117632Sharti{
184117632Sharti	patm_debug(sc, VCC, "%u.%u RX finally closed",
185117632Sharti	    vcc->vcc.vpi, vcc->vcc.vci);
186117632Sharti}
187117632Sharti
188117632Sharti/*
189117632Sharti * Handle the given receive status queue entry
190117632Sharti */
191117632Shartivoid
192117632Shartipatm_rx(struct patm_softc *sc, struct idt_rsqe *rsqe)
193117632Sharti{
194117632Sharti	struct mbuf *m;
195117632Sharti	void *buf;
196117632Sharti	u_int stat, cid, w, cells, len, h;
197117632Sharti	struct patm_vcc *vcc;
198117632Sharti	struct atm_pseudohdr aph;
199117632Sharti	u_char *trail;
200117632Sharti
201117632Sharti	cid = le32toh(rsqe->cid);
202117632Sharti	stat = le32toh(rsqe->stat);
203117632Sharti	h = le32toh(rsqe->handle);
204117632Sharti
205117632Sharti	cid = PATM_CID(sc, IDT_RSQE_VPI(cid), IDT_RSQE_VCI(cid));
206117632Sharti	vcc = sc->vccs[cid];
207117632Sharti
208117632Sharti	if (IDT_RSQE_TYPE(stat) == IDT_RSQE_IDLE) {
209117632Sharti		/* connection has gone idle */
210117632Sharti		if (stat & IDT_RSQE_BUF)
211117632Sharti			patm_rcv_free(sc, patm_rcv_handle(sc, h), h);
212117632Sharti
213117632Sharti		w = rct_read(sc, cid, 0);
214117632Sharti		if (w != 0 && !(w & IDT_RCT_OPEN))
215117632Sharti			rct_write(sc, cid, 0, 0);
216117632Sharti		if (vcc != NULL && (vcc->vflags & PATM_VCC_RX_CLOSING)) {
217117632Sharti			patm_debug(sc, VCC, "%u.%u RX closed", vcc->vcc.vpi,
218117632Sharti			    vcc->vcc.vci);
219117632Sharti			vcc->vflags &= ~PATM_VCC_RX_CLOSING;
220118539Sharti			if (vcc->vcc.flags & ATMIO_FLAG_ASYNC) {
221117632Sharti				patm_rx_vcc_closed(sc, vcc);
222117632Sharti				if (!(vcc->vflags & PATM_VCC_OPEN))
223117632Sharti					patm_vcc_closed(sc, vcc);
224117632Sharti			} else
225117632Sharti				cv_signal(&sc->vcc_cv);
226117632Sharti		}
227117632Sharti		return;
228117632Sharti	}
229117632Sharti
230117632Sharti	buf = patm_rcv_handle(sc, h);
231117632Sharti
232117632Sharti	if (vcc == NULL || (vcc->vflags & PATM_VCC_RX_OPEN) == 0) {
233117632Sharti		patm_rcv_free(sc, buf, h);
234117632Sharti		return;
235117632Sharti	}
236117632Sharti
237117632Sharti	cells = IDT_RSQE_CNT(stat);
238117632Sharti	KASSERT(cells > 0, ("zero cell count"));
239117632Sharti
240117632Sharti	if (vcc->vcc.aal == ATMIO_AAL_0) {
241117632Sharti		/* deliver this packet as it is */
242117632Sharti		if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
243117632Sharti			return;
244117632Sharti
245117632Sharti		m->m_len = cells * 48;
246117632Sharti		m->m_pkthdr.len = m->m_len;
247147256Sbrooks		m->m_pkthdr.rcvif = sc->ifp;
248117632Sharti
249117632Sharti	} else if (vcc->vcc.aal == ATMIO_AAL_34) {
250117632Sharti		/* XXX AAL3/4 */
251117632Sharti		patm_rcv_free(sc, buf, h);
252117632Sharti		return;
253117632Sharti
254117632Sharti	} else if (vcc->vcc.aal == ATMIO_AAL_5) {
255117632Sharti		if (stat & IDT_RSQE_CRC) {
256147256Sbrooks			sc->ifp->if_ierrors++;
257117632Sharti			if (vcc->chain != NULL) {
258117632Sharti				m_freem(vcc->chain);
259117632Sharti				vcc->chain = vcc->last = NULL;
260117632Sharti			}
261117632Sharti			return;
262117632Sharti		}
263117632Sharti
264117632Sharti		/* append to current chain */
265117632Sharti		if (vcc->chain == NULL) {
266117632Sharti			if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
267117632Sharti				return;
268117632Sharti			m->m_len = cells * 48;
269117632Sharti			m->m_pkthdr.len = m->m_len;
270147256Sbrooks			m->m_pkthdr.rcvif = sc->ifp;
271117632Sharti			vcc->chain = vcc->last = m;
272117632Sharti		} else {
273117632Sharti			if ((m = patm_rcv_mbuf(sc, buf, h, 0)) == NULL)
274117632Sharti				return;
275117632Sharti			m->m_len = cells * 48;
276117632Sharti			vcc->last->m_next = m;
277117632Sharti			vcc->last = m;
278117632Sharti			vcc->chain->m_pkthdr.len += m->m_len;
279117632Sharti		}
280117632Sharti
281117632Sharti		if (!(stat & IDT_RSQE_EPDU))
282117632Sharti			return;
283117632Sharti
284117632Sharti		trail = mtod(m, u_char *) + m->m_len - 6;
285117632Sharti		len = (trail[0] << 8) + trail[1];
286117632Sharti
287117632Sharti		if ((u_int)vcc->chain->m_pkthdr.len < len + 8) {
288117632Sharti			patm_printf(sc, "%s: bad aal5 lengths %u %u\n",
289117632Sharti			    __func__, (u_int)m->m_pkthdr.len, len);
290117632Sharti			m_freem(vcc->chain);
291117632Sharti			vcc->chain = vcc->last = NULL;
292117632Sharti			return;
293117632Sharti		}
294117632Sharti		m->m_len -= vcc->chain->m_pkthdr.len - len;
295117632Sharti		KASSERT(m->m_len >= 0, ("bad last mbuf"));
296117632Sharti
297117632Sharti		m = vcc->chain;
298117632Sharti		vcc->chain = vcc->last = NULL;
299117632Sharti		m->m_pkthdr.len = len;
300117632Sharti	} else
301117632Sharti		panic("bad aal");
302117632Sharti
303117632Sharti#if 0
304117632Sharti	{
305117632Sharti		u_int i;
306117632Sharti
307117632Sharti		for (i = 0; i < m->m_len; i++) {
308117632Sharti			printf("%02x ", mtod(m, u_char *)[i]);
309117632Sharti		}
310117632Sharti		printf("\n");
311117632Sharti	}
312117632Sharti#endif
313117632Sharti
314147256Sbrooks	sc->ifp->if_ipackets++;
315117632Sharti	/* this is in if_atmsubr.c */
316147256Sbrooks	/* sc->ifp->if_ibytes += m->m_pkthdr.len; */
317117632Sharti
318117632Sharti	vcc->ibytes += m->m_pkthdr.len;
319117632Sharti	vcc->ipackets++;
320117632Sharti
321117632Sharti	ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
322117632Sharti	ATM_PH_VPI(&aph) = IDT_RSQE_VPI(cid);
323117632Sharti	ATM_PH_SETVCI(&aph, IDT_RSQE_VCI(cid));
324117632Sharti
325117632Sharti#ifdef ENABLE_BPF
326117632Sharti	if (!(vcc->vcc.flags & ATMIO_FLAG_NG) &&
327118539Sharti	    (vcc->vcc.aal == ATMIO_AAL_5) &&
328117632Sharti	    (vcc->vcc.flags & ATM_PH_LLCSNAP))
329147256Sbrooks		BPF_MTAP(sc->ifp, m);
330117632Sharti#endif
331117632Sharti
332147256Sbrooks	atm_input(sc->ifp, &aph, m, vcc->rxhand);
333117632Sharti}
334117632Sharti
335117632Sharti/*
336117632Sharti * Get the buffer for a receive handle. This is either an mbuf for
337117632Sharti * a large handle or a pool buffer for the others.
338117632Sharti */
339117632Shartistatic void *
340117632Shartipatm_rcv_handle(struct patm_softc *sc, u_int handle)
341117632Sharti{
342117632Sharti	void *buf;
343117632Sharti	u_int c;
344117632Sharti
345117632Sharti	if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE) {
346117632Sharti		struct lmbuf *b;
347117632Sharti
348117632Sharti		c = handle & MBUF_HMASK;
349117632Sharti		b = &sc->lbufs[c];
350117632Sharti
351117632Sharti		buf = b->m;
352117632Sharti		b->m = NULL;
353117632Sharti
354117632Sharti		bus_dmamap_sync(sc->lbuf_tag, b->map, BUS_DMASYNC_POSTREAD);
355117632Sharti		patm_lbuf_free(sc, b);
356117632Sharti
357117632Sharti	} else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE) {
358117632Sharti		mbp_sync(sc->vbuf_pool, handle,
359117632Sharti		    0, VMBUF_SIZE, BUS_DMASYNC_POSTREAD);
360117632Sharti		buf = mbp_get(sc->vbuf_pool, handle);
361117632Sharti
362117632Sharti	} else {
363117632Sharti		mbp_sync(sc->sbuf_pool, handle,
364117632Sharti		    0, SMBUF_SIZE, BUS_DMASYNC_POSTREAD);
365117632Sharti		buf = mbp_get(sc->sbuf_pool, handle);
366117632Sharti	}
367117632Sharti
368117632Sharti	return (buf);
369117632Sharti}
370117632Sharti
371117632Sharti/*
372117632Sharti * Free a buffer.
373117632Sharti */
374117632Shartistatic void
375117632Shartipatm_rcv_free(struct patm_softc *sc, void *p, u_int handle)
376117632Sharti{
377117632Sharti	if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE)
378117632Sharti		m_free((struct mbuf *)p);
379117632Sharti
380117632Sharti	else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE)
381117632Sharti		mbp_free(sc->vbuf_pool, p);
382117632Sharti
383117632Sharti	else
384117632Sharti		mbp_free(sc->sbuf_pool, p);
385117632Sharti}
386117632Sharti
387117632Sharti/*
388117632Sharti * Make an mbuf around the buffer
389117632Sharti */
390117632Shartistatic struct mbuf *
391117632Shartipatm_rcv_mbuf(struct patm_softc *sc, void *buf, u_int h, int hdr)
392117632Sharti{
393117632Sharti	struct mbuf *m;
394117632Sharti
395117632Sharti	if ((h & ~MBUF_HMASK) == MBUF_LHANDLE)
396117632Sharti		return ((struct mbuf *)buf);
397117632Sharti
398117632Sharti	if (hdr)
399243857Sglebius		MGETHDR(m, M_NOWAIT, MT_DATA);
400117632Sharti	else
401243857Sglebius		MGET(m, M_NOWAIT, MT_DATA);
402117632Sharti	if (m == NULL) {
403117632Sharti		patm_rcv_free(sc, buf, h);
404117632Sharti		return (NULL);
405117632Sharti	}
406117632Sharti
407117632Sharti	if ((h & ~MBUF_HMASK) == MBUF_VHANDLE) {
408150347Sandre		MEXTADD(m, (caddr_t)buf, VMBUF_SIZE, mbp_ext_free,
409175872Sphk		    buf, sc->vbuf_pool, M_PKTHDR, EXT_NET_DRV);
410117632Sharti		m->m_data += VMBUF_OFFSET;
411117632Sharti	} else {
412150347Sandre		MEXTADD(m, (caddr_t)buf, SMBUF_SIZE, mbp_ext_free,
413175872Sphk		    buf, sc->sbuf_pool, M_PKTHDR, EXT_NET_DRV);
414117632Sharti		m->m_data += SMBUF_OFFSET;
415117632Sharti	}
416117632Sharti
417117632Sharti	if (!(m->m_flags & M_EXT)) {
418117632Sharti		patm_rcv_free(sc, buf, h);
419117632Sharti		m_free(m);
420117632Sharti		return (NULL);
421117632Sharti	}
422117632Sharti	return (m);
423117632Sharti}
424117632Sharti
425117632Sharti/*
426117632Sharti * Process the raw cell at the given address.
427117632Sharti */
428117632Shartivoid
429117632Shartipatm_rx_raw(struct patm_softc *sc, u_char *cell)
430117632Sharti{
431117632Sharti	u_int vpi, vci, cid;
432117632Sharti	struct patm_vcc *vcc;
433117632Sharti	struct mbuf *m;
434117632Sharti	u_char *dst;
435117632Sharti	struct timespec ts;
436117632Sharti	struct atm_pseudohdr aph;
437117632Sharti	uint64_t cts;
438117632Sharti
439117632Sharti	sc->stats.raw_cells++;
440117632Sharti
441117632Sharti	/*
442117632Sharti	 * For some non-appearant reason the cell header
443117632Sharti	 * is in the wrong endian.
444117632Sharti	 */
445117632Sharti	*(uint32_t *)cell = bswap32(*(uint32_t *)cell);
446117632Sharti
447117632Sharti	vpi = ((cell[0] & 0xf) << 4) | ((cell[1] & 0xf0) >> 4);
448117632Sharti	vci = ((cell[1] & 0xf) << 12) | (cell[2] << 4) | ((cell[3] & 0xf0) >> 4);
449117632Sharti	cid = PATM_CID(sc, vpi, vci);
450117632Sharti
451117632Sharti	vcc = sc->vccs[cid];
452117632Sharti	if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN) ||
453117632Sharti	    vcc->vcc.aal != ATMIO_AAL_RAW) {
454117632Sharti		vcc = sc->vccs[0];
455117632Sharti		if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN)) {
456117632Sharti			sc->stats.raw_no_vcc++;
457117632Sharti			return;
458117632Sharti		}
459117632Sharti	}
460117632Sharti
461243857Sglebius	MGETHDR(m, M_NOWAIT, MT_DATA);
462117632Sharti	if (m == NULL) {
463117632Sharti		sc->stats.raw_no_buf++;
464117632Sharti		return;
465117632Sharti	}
466147256Sbrooks	m->m_pkthdr.rcvif = sc->ifp;
467117632Sharti
468117632Sharti	switch (vcc->vflags & PATM_RAW_FORMAT) {
469117632Sharti
470117632Sharti	  default:
471117632Sharti	  case PATM_RAW_CELL:
472117632Sharti		m->m_len = m->m_pkthdr.len = 53;
473117632Sharti		MH_ALIGN(m, 53);
474117632Sharti		dst = mtod(m, u_char *);
475117632Sharti		*dst++ = *cell++;
476117632Sharti		*dst++ = *cell++;
477117632Sharti		*dst++ = *cell++;
478117632Sharti		*dst++ = *cell++;
479117632Sharti		*dst++ = 0;		/* HEC */
480117632Sharti		bcopy(cell + 12, dst, 48);
481117632Sharti		break;
482117632Sharti
483117632Sharti	  case PATM_RAW_NOHEC:
484117632Sharti		m->m_len = m->m_pkthdr.len = 52;
485117632Sharti		MH_ALIGN(m, 52);
486117632Sharti		dst = mtod(m, u_char *);
487117632Sharti		*dst++ = *cell++;
488117632Sharti		*dst++ = *cell++;
489117632Sharti		*dst++ = *cell++;
490117632Sharti		*dst++ = *cell++;
491117632Sharti		bcopy(cell + 12, dst, 48);
492117632Sharti		break;
493117632Sharti
494117632Sharti	  case PATM_RAW_CS:
495117632Sharti		m->m_len = m->m_pkthdr.len = 64;
496117632Sharti		MH_ALIGN(m, 64);
497117632Sharti		dst = mtod(m, u_char *);
498117632Sharti		*dst++ = *cell++;
499117632Sharti		*dst++ = *cell++;
500117632Sharti		*dst++ = *cell++;
501117632Sharti		*dst++ = *cell++;
502117632Sharti		*dst++ = 0;		/* HEC */
503117632Sharti		*dst++ = 0;		/* flags */
504117632Sharti		*dst++ = 0;		/* reserved */
505117632Sharti		*dst++ = 0;		/* reserved */
506117632Sharti		nanotime(&ts);
507117632Sharti		cts = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
508117632Sharti		bcopy(dst, &cts, 8);
509117632Sharti		bcopy(cell + 12, dst + 8, 48);
510117632Sharti		break;
511117632Sharti	}
512117632Sharti
513147256Sbrooks	sc->ifp->if_ipackets++;
514117632Sharti	/* this is in if_atmsubr.c */
515147256Sbrooks	/* sc->ifp->if_ibytes += m->m_pkthdr.len; */
516117632Sharti
517117632Sharti	vcc->ibytes += m->m_pkthdr.len;
518117632Sharti	vcc->ipackets++;
519117632Sharti
520117632Sharti	ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
521117632Sharti	ATM_PH_VPI(&aph) = vcc->vcc.vpi;
522117632Sharti	ATM_PH_SETVCI(&aph, vcc->vcc.vci);
523117632Sharti
524147256Sbrooks	atm_input(sc->ifp, &aph, m, vcc->rxhand);
525117632Sharti}
526