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$");
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>
60257176Sglebius#include <net/if_var.h>
61117632Sharti#include <net/if_media.h>
62117632Sharti#include <net/if_atm.h>
63117632Sharti#include <net/route.h>
64117632Sharti#ifdef ENABLE_BPF
65117632Sharti#include <net/bpf.h>
66117632Sharti#endif
67117632Sharti#include <netinet/in.h>
68117632Sharti#include <netinet/if_atm.h>
69117632Sharti
70117632Sharti#include <machine/bus.h>
71117632Sharti#include <machine/resource.h>
72117632Sharti#include <sys/bus.h>
73117632Sharti#include <sys/rman.h>
74117632Sharti#include <sys/mbpool.h>
75117632Sharti
76117632Sharti#include <dev/utopia/utopia.h>
77117632Sharti#include <dev/patm/idt77252reg.h>
78117632Sharti#include <dev/patm/if_patmvar.h>
79117632Sharti
80117632Shartistatic void *patm_rcv_handle(struct patm_softc *sc, u_int handle);
81117632Shartistatic void patm_rcv_free(struct patm_softc *, void *, u_int handle);
82117632Shartistatic struct mbuf *patm_rcv_mbuf(struct patm_softc *, void *, u_int, int);
83117632Sharti
84117632Shartistatic __inline void
85117632Shartirct_write(struct patm_softc *sc, u_int cid, u_int w, u_int val)
86117632Sharti{
87117632Sharti	patm_sram_write(sc, sc->mmap->rct + cid * IDT_RCT_ENTRY_SIZE + w, val);
88117632Sharti}
89117632Shartistatic __inline u_int
90117632Shartirct_read(struct patm_softc *sc, u_int cid, u_int w)
91117632Sharti{
92117632Sharti	return (patm_sram_read(sc, sc->mmap->rct +
93117632Sharti	    cid * IDT_RCT_ENTRY_SIZE + w));
94117632Sharti}
95117632Sharti
96117632Sharti/* check if we can open this one */
97117632Shartiint
98117632Shartipatm_rx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc)
99117632Sharti{
100117632Sharti	return (0);
101117632Sharti}
102117632Sharti
103117632Sharti/*
104117632Sharti * open the VCC
105117632Sharti */
106117632Shartivoid
107117632Shartipatm_rx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc)
108117632Sharti{
109117632Sharti	uint32_t w1 = IDT_RCT_OPEN;
110117632Sharti
111117632Sharti	patm_debug(sc, VCC, "%u.%u RX opening", vcc->vcc.vpi, vcc->vcc.vci);
112117632Sharti
113117632Sharti	switch (vcc->vcc.aal) {
114117632Sharti	  case ATMIO_AAL_0:
115117632Sharti		w1 |= IDT_RCT_AAL0 | IDT_RCT_FBP2 | IDT_RCT_RCI;
116117632Sharti		break;
117117632Sharti	  case ATMIO_AAL_34:
118117632Sharti		w1 |= IDT_RCT_AAL34;
119117632Sharti		break;
120117632Sharti	  case ATMIO_AAL_5:
121117632Sharti		w1 |= IDT_RCT_AAL5;
122117632Sharti		break;
123117632Sharti	  case ATMIO_AAL_RAW:
124117632Sharti		w1 |= IDT_RCT_AALRAW | IDT_RCT_RCI;
125117632Sharti		break;
126117632Sharti	}
127117632Sharti
128117632Sharti	if (vcc->cid != 0)
129118061Sharti		patm_sram_write4(sc, sc->mmap->rct + vcc->cid *
130118061Sharti		    IDT_RCT_ENTRY_SIZE, w1, 0, 0, 0xffffffff);
131117632Sharti	else {
132117632Sharti		/* switch the interface into promiscuous mode */
133117632Sharti		patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) |
134117632Sharti		    IDT_CFG_ICAPT | IDT_CFG_VPECA);
135117632Sharti	}
136117632Sharti
137117632Sharti	vcc->vflags |= PATM_VCC_RX_OPEN;
138117632Sharti}
139117632Sharti
140117632Sharti/* close the given vcc for transmission */
141117632Shartivoid
142117632Shartipatm_rx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc)
143117632Sharti{
144117632Sharti	u_int w1;
145117632Sharti
146117632Sharti	patm_debug(sc, VCC, "%u.%u RX closing", vcc->vcc.vpi, vcc->vcc.vci);
147117632Sharti
148117632Sharti	if (vcc->cid == 0) {
149117632Sharti		/* switch off promiscuous mode */
150117632Sharti		patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) &
151117632Sharti		    ~(IDT_CFG_ICAPT | IDT_CFG_VPECA));
152117632Sharti		vcc->vflags &= ~PATM_VCC_RX_OPEN;
153117632Sharti		return;
154117632Sharti	}
155117632Sharti
156117632Sharti	/* close the connection but keep state */
157117632Sharti	w1 = rct_read(sc, vcc->cid, 0);
158117632Sharti	w1 &= ~IDT_RCT_OPEN;
159117632Sharti	rct_write(sc, vcc->cid, 0, w1);
160117632Sharti
161117632Sharti	/* minimum idle count */
162117632Sharti	w1 = (w1 & ~IDT_RCT_IACT_CNT_MASK) | (1 << IDT_RCT_IACT_CNT_SHIFT);
163117632Sharti	rct_write(sc, vcc->cid, 0, w1);
164117632Sharti
165117632Sharti	/* initialize scan */
166117632Sharti	patm_nor_write(sc, IDT_NOR_IRCP, vcc->cid);
167117632Sharti
168117632Sharti	vcc->vflags &= ~PATM_VCC_RX_OPEN;
169117632Sharti	vcc->vflags |= PATM_VCC_RX_CLOSING;
170117632Sharti
171117632Sharti	/*
172117632Sharti	 * check the RSQ
173117632Sharti	 * This is a hack. The problem is, that although an entry is written
174117632Sharti	 * to the RSQ, no interrupt is generated. Also we must wait 1 cell
175117632Sharti	 * time for the SAR to process the scan of our connection.
176117632Sharti	 */
177117632Sharti	DELAY(1);
178117632Sharti	patm_intr_rsq(sc);
179117632Sharti}
180117632Sharti
181117632Sharti/* transmission side finally closed */
182117632Shartivoid
183117632Shartipatm_rx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
184117632Sharti{
185117632Sharti	patm_debug(sc, VCC, "%u.%u RX finally closed",
186117632Sharti	    vcc->vcc.vpi, vcc->vcc.vci);
187117632Sharti}
188117632Sharti
189117632Sharti/*
190117632Sharti * Handle the given receive status queue entry
191117632Sharti */
192117632Shartivoid
193117632Shartipatm_rx(struct patm_softc *sc, struct idt_rsqe *rsqe)
194117632Sharti{
195117632Sharti	struct mbuf *m;
196117632Sharti	void *buf;
197117632Sharti	u_int stat, cid, w, cells, len, h;
198117632Sharti	struct patm_vcc *vcc;
199117632Sharti	struct atm_pseudohdr aph;
200117632Sharti	u_char *trail;
201117632Sharti
202117632Sharti	cid = le32toh(rsqe->cid);
203117632Sharti	stat = le32toh(rsqe->stat);
204117632Sharti	h = le32toh(rsqe->handle);
205117632Sharti
206117632Sharti	cid = PATM_CID(sc, IDT_RSQE_VPI(cid), IDT_RSQE_VCI(cid));
207117632Sharti	vcc = sc->vccs[cid];
208117632Sharti
209117632Sharti	if (IDT_RSQE_TYPE(stat) == IDT_RSQE_IDLE) {
210117632Sharti		/* connection has gone idle */
211117632Sharti		if (stat & IDT_RSQE_BUF)
212117632Sharti			patm_rcv_free(sc, patm_rcv_handle(sc, h), h);
213117632Sharti
214117632Sharti		w = rct_read(sc, cid, 0);
215117632Sharti		if (w != 0 && !(w & IDT_RCT_OPEN))
216117632Sharti			rct_write(sc, cid, 0, 0);
217117632Sharti		if (vcc != NULL && (vcc->vflags & PATM_VCC_RX_CLOSING)) {
218117632Sharti			patm_debug(sc, VCC, "%u.%u RX closed", vcc->vcc.vpi,
219117632Sharti			    vcc->vcc.vci);
220117632Sharti			vcc->vflags &= ~PATM_VCC_RX_CLOSING;
221118539Sharti			if (vcc->vcc.flags & ATMIO_FLAG_ASYNC) {
222117632Sharti				patm_rx_vcc_closed(sc, vcc);
223117632Sharti				if (!(vcc->vflags & PATM_VCC_OPEN))
224117632Sharti					patm_vcc_closed(sc, vcc);
225117632Sharti			} else
226117632Sharti				cv_signal(&sc->vcc_cv);
227117632Sharti		}
228117632Sharti		return;
229117632Sharti	}
230117632Sharti
231117632Sharti	buf = patm_rcv_handle(sc, h);
232117632Sharti
233117632Sharti	if (vcc == NULL || (vcc->vflags & PATM_VCC_RX_OPEN) == 0) {
234117632Sharti		patm_rcv_free(sc, buf, h);
235117632Sharti		return;
236117632Sharti	}
237117632Sharti
238117632Sharti	cells = IDT_RSQE_CNT(stat);
239117632Sharti	KASSERT(cells > 0, ("zero cell count"));
240117632Sharti
241117632Sharti	if (vcc->vcc.aal == ATMIO_AAL_0) {
242117632Sharti		/* deliver this packet as it is */
243117632Sharti		if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
244117632Sharti			return;
245117632Sharti
246117632Sharti		m->m_len = cells * 48;
247117632Sharti		m->m_pkthdr.len = m->m_len;
248147256Sbrooks		m->m_pkthdr.rcvif = sc->ifp;
249117632Sharti
250117632Sharti	} else if (vcc->vcc.aal == ATMIO_AAL_34) {
251117632Sharti		/* XXX AAL3/4 */
252117632Sharti		patm_rcv_free(sc, buf, h);
253117632Sharti		return;
254117632Sharti
255117632Sharti	} else if (vcc->vcc.aal == ATMIO_AAL_5) {
256117632Sharti		if (stat & IDT_RSQE_CRC) {
257271849Sglebius			if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
258117632Sharti			if (vcc->chain != NULL) {
259117632Sharti				m_freem(vcc->chain);
260117632Sharti				vcc->chain = vcc->last = NULL;
261117632Sharti			}
262117632Sharti			return;
263117632Sharti		}
264117632Sharti
265117632Sharti		/* append to current chain */
266117632Sharti		if (vcc->chain == NULL) {
267117632Sharti			if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
268117632Sharti				return;
269117632Sharti			m->m_len = cells * 48;
270117632Sharti			m->m_pkthdr.len = m->m_len;
271147256Sbrooks			m->m_pkthdr.rcvif = sc->ifp;
272117632Sharti			vcc->chain = vcc->last = m;
273117632Sharti		} else {
274117632Sharti			if ((m = patm_rcv_mbuf(sc, buf, h, 0)) == NULL)
275117632Sharti				return;
276117632Sharti			m->m_len = cells * 48;
277117632Sharti			vcc->last->m_next = m;
278117632Sharti			vcc->last = m;
279117632Sharti			vcc->chain->m_pkthdr.len += m->m_len;
280117632Sharti		}
281117632Sharti
282117632Sharti		if (!(stat & IDT_RSQE_EPDU))
283117632Sharti			return;
284117632Sharti
285117632Sharti		trail = mtod(m, u_char *) + m->m_len - 6;
286117632Sharti		len = (trail[0] << 8) + trail[1];
287117632Sharti
288117632Sharti		if ((u_int)vcc->chain->m_pkthdr.len < len + 8) {
289117632Sharti			patm_printf(sc, "%s: bad aal5 lengths %u %u\n",
290117632Sharti			    __func__, (u_int)m->m_pkthdr.len, len);
291117632Sharti			m_freem(vcc->chain);
292117632Sharti			vcc->chain = vcc->last = NULL;
293117632Sharti			return;
294117632Sharti		}
295117632Sharti		m->m_len -= vcc->chain->m_pkthdr.len - len;
296117632Sharti		KASSERT(m->m_len >= 0, ("bad last mbuf"));
297117632Sharti
298117632Sharti		m = vcc->chain;
299117632Sharti		vcc->chain = vcc->last = NULL;
300117632Sharti		m->m_pkthdr.len = len;
301117632Sharti	} else
302117632Sharti		panic("bad aal");
303117632Sharti
304117632Sharti#if 0
305117632Sharti	{
306117632Sharti		u_int i;
307117632Sharti
308117632Sharti		for (i = 0; i < m->m_len; i++) {
309117632Sharti			printf("%02x ", mtod(m, u_char *)[i]);
310117632Sharti		}
311117632Sharti		printf("\n");
312117632Sharti	}
313117632Sharti#endif
314117632Sharti
315271849Sglebius	if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
316117632Sharti	/* this is in if_atmsubr.c */
317271849Sglebius	/* if_inc_counter(sc->ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); */
318117632Sharti
319117632Sharti	vcc->ibytes += m->m_pkthdr.len;
320117632Sharti	vcc->ipackets++;
321117632Sharti
322117632Sharti	ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
323117632Sharti	ATM_PH_VPI(&aph) = IDT_RSQE_VPI(cid);
324117632Sharti	ATM_PH_SETVCI(&aph, IDT_RSQE_VCI(cid));
325117632Sharti
326117632Sharti#ifdef ENABLE_BPF
327117632Sharti	if (!(vcc->vcc.flags & ATMIO_FLAG_NG) &&
328118539Sharti	    (vcc->vcc.aal == ATMIO_AAL_5) &&
329117632Sharti	    (vcc->vcc.flags & ATM_PH_LLCSNAP))
330147256Sbrooks		BPF_MTAP(sc->ifp, m);
331117632Sharti#endif
332117632Sharti
333147256Sbrooks	atm_input(sc->ifp, &aph, m, vcc->rxhand);
334117632Sharti}
335117632Sharti
336117632Sharti/*
337117632Sharti * Get the buffer for a receive handle. This is either an mbuf for
338117632Sharti * a large handle or a pool buffer for the others.
339117632Sharti */
340117632Shartistatic void *
341117632Shartipatm_rcv_handle(struct patm_softc *sc, u_int handle)
342117632Sharti{
343117632Sharti	void *buf;
344117632Sharti	u_int c;
345117632Sharti
346117632Sharti	if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE) {
347117632Sharti		struct lmbuf *b;
348117632Sharti
349117632Sharti		c = handle & MBUF_HMASK;
350117632Sharti		b = &sc->lbufs[c];
351117632Sharti
352117632Sharti		buf = b->m;
353117632Sharti		b->m = NULL;
354117632Sharti
355117632Sharti		bus_dmamap_sync(sc->lbuf_tag, b->map, BUS_DMASYNC_POSTREAD);
356117632Sharti		patm_lbuf_free(sc, b);
357117632Sharti
358117632Sharti	} else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE) {
359117632Sharti		mbp_sync(sc->vbuf_pool, handle,
360117632Sharti		    0, VMBUF_SIZE, BUS_DMASYNC_POSTREAD);
361117632Sharti		buf = mbp_get(sc->vbuf_pool, handle);
362117632Sharti
363117632Sharti	} else {
364117632Sharti		mbp_sync(sc->sbuf_pool, handle,
365117632Sharti		    0, SMBUF_SIZE, BUS_DMASYNC_POSTREAD);
366117632Sharti		buf = mbp_get(sc->sbuf_pool, handle);
367117632Sharti	}
368117632Sharti
369117632Sharti	return (buf);
370117632Sharti}
371117632Sharti
372117632Sharti/*
373117632Sharti * Free a buffer.
374117632Sharti */
375117632Shartistatic void
376117632Shartipatm_rcv_free(struct patm_softc *sc, void *p, u_int handle)
377117632Sharti{
378117632Sharti	if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE)
379117632Sharti		m_free((struct mbuf *)p);
380117632Sharti
381117632Sharti	else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE)
382117632Sharti		mbp_free(sc->vbuf_pool, p);
383117632Sharti
384117632Sharti	else
385117632Sharti		mbp_free(sc->sbuf_pool, p);
386117632Sharti}
387117632Sharti
388117632Sharti/*
389117632Sharti * Make an mbuf around the buffer
390117632Sharti */
391117632Shartistatic struct mbuf *
392117632Shartipatm_rcv_mbuf(struct patm_softc *sc, void *buf, u_int h, int hdr)
393117632Sharti{
394117632Sharti	struct mbuf *m;
395117632Sharti
396117632Sharti	if ((h & ~MBUF_HMASK) == MBUF_LHANDLE)
397117632Sharti		return ((struct mbuf *)buf);
398117632Sharti
399117632Sharti	if (hdr)
400243857Sglebius		MGETHDR(m, M_NOWAIT, MT_DATA);
401117632Sharti	else
402243857Sglebius		MGET(m, M_NOWAIT, MT_DATA);
403117632Sharti	if (m == NULL) {
404117632Sharti		patm_rcv_free(sc, buf, h);
405117632Sharti		return (NULL);
406117632Sharti	}
407117632Sharti
408117632Sharti	if ((h & ~MBUF_HMASK) == MBUF_VHANDLE) {
409150347Sandre		MEXTADD(m, (caddr_t)buf, VMBUF_SIZE, mbp_ext_free,
410175872Sphk		    buf, sc->vbuf_pool, M_PKTHDR, EXT_NET_DRV);
411117632Sharti		m->m_data += VMBUF_OFFSET;
412117632Sharti	} else {
413150347Sandre		MEXTADD(m, (caddr_t)buf, SMBUF_SIZE, mbp_ext_free,
414175872Sphk		    buf, sc->sbuf_pool, M_PKTHDR, EXT_NET_DRV);
415117632Sharti		m->m_data += SMBUF_OFFSET;
416117632Sharti	}
417117632Sharti
418117632Sharti	if (!(m->m_flags & M_EXT)) {
419117632Sharti		patm_rcv_free(sc, buf, h);
420117632Sharti		m_free(m);
421117632Sharti		return (NULL);
422117632Sharti	}
423117632Sharti	return (m);
424117632Sharti}
425117632Sharti
426117632Sharti/*
427117632Sharti * Process the raw cell at the given address.
428117632Sharti */
429117632Shartivoid
430117632Shartipatm_rx_raw(struct patm_softc *sc, u_char *cell)
431117632Sharti{
432117632Sharti	u_int vpi, vci, cid;
433117632Sharti	struct patm_vcc *vcc;
434117632Sharti	struct mbuf *m;
435117632Sharti	u_char *dst;
436117632Sharti	struct timespec ts;
437117632Sharti	struct atm_pseudohdr aph;
438117632Sharti	uint64_t cts;
439117632Sharti
440117632Sharti	sc->stats.raw_cells++;
441117632Sharti
442117632Sharti	/*
443117632Sharti	 * For some non-appearant reason the cell header
444117632Sharti	 * is in the wrong endian.
445117632Sharti	 */
446117632Sharti	*(uint32_t *)cell = bswap32(*(uint32_t *)cell);
447117632Sharti
448117632Sharti	vpi = ((cell[0] & 0xf) << 4) | ((cell[1] & 0xf0) >> 4);
449117632Sharti	vci = ((cell[1] & 0xf) << 12) | (cell[2] << 4) | ((cell[3] & 0xf0) >> 4);
450117632Sharti	cid = PATM_CID(sc, vpi, vci);
451117632Sharti
452117632Sharti	vcc = sc->vccs[cid];
453117632Sharti	if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN) ||
454117632Sharti	    vcc->vcc.aal != ATMIO_AAL_RAW) {
455117632Sharti		vcc = sc->vccs[0];
456117632Sharti		if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN)) {
457117632Sharti			sc->stats.raw_no_vcc++;
458117632Sharti			return;
459117632Sharti		}
460117632Sharti	}
461117632Sharti
462243857Sglebius	MGETHDR(m, M_NOWAIT, MT_DATA);
463117632Sharti	if (m == NULL) {
464117632Sharti		sc->stats.raw_no_buf++;
465117632Sharti		return;
466117632Sharti	}
467147256Sbrooks	m->m_pkthdr.rcvif = sc->ifp;
468117632Sharti
469117632Sharti	switch (vcc->vflags & PATM_RAW_FORMAT) {
470117632Sharti
471117632Sharti	  default:
472117632Sharti	  case PATM_RAW_CELL:
473117632Sharti		m->m_len = m->m_pkthdr.len = 53;
474276692Srwatson		M_ALIGN(m, 53);
475117632Sharti		dst = mtod(m, u_char *);
476117632Sharti		*dst++ = *cell++;
477117632Sharti		*dst++ = *cell++;
478117632Sharti		*dst++ = *cell++;
479117632Sharti		*dst++ = *cell++;
480117632Sharti		*dst++ = 0;		/* HEC */
481117632Sharti		bcopy(cell + 12, dst, 48);
482117632Sharti		break;
483117632Sharti
484117632Sharti	  case PATM_RAW_NOHEC:
485117632Sharti		m->m_len = m->m_pkthdr.len = 52;
486276692Srwatson		M_ALIGN(m, 52);
487117632Sharti		dst = mtod(m, u_char *);
488117632Sharti		*dst++ = *cell++;
489117632Sharti		*dst++ = *cell++;
490117632Sharti		*dst++ = *cell++;
491117632Sharti		*dst++ = *cell++;
492117632Sharti		bcopy(cell + 12, dst, 48);
493117632Sharti		break;
494117632Sharti
495117632Sharti	  case PATM_RAW_CS:
496117632Sharti		m->m_len = m->m_pkthdr.len = 64;
497276692Srwatson		M_ALIGN(m, 64);
498117632Sharti		dst = mtod(m, u_char *);
499117632Sharti		*dst++ = *cell++;
500117632Sharti		*dst++ = *cell++;
501117632Sharti		*dst++ = *cell++;
502117632Sharti		*dst++ = *cell++;
503117632Sharti		*dst++ = 0;		/* HEC */
504117632Sharti		*dst++ = 0;		/* flags */
505117632Sharti		*dst++ = 0;		/* reserved */
506117632Sharti		*dst++ = 0;		/* reserved */
507117632Sharti		nanotime(&ts);
508117632Sharti		cts = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
509117632Sharti		bcopy(dst, &cts, 8);
510117632Sharti		bcopy(cell + 12, dst + 8, 48);
511117632Sharti		break;
512117632Sharti	}
513117632Sharti
514271849Sglebius	if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
515117632Sharti	/* this is in if_atmsubr.c */
516271849Sglebius	/* if_inc_counter(sc->ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); */
517117632Sharti
518117632Sharti	vcc->ibytes += m->m_pkthdr.len;
519117632Sharti	vcc->ipackets++;
520117632Sharti
521117632Sharti	ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
522117632Sharti	ATM_PH_VPI(&aph) = vcc->vcc.vpi;
523117632Sharti	ATM_PH_SETVCI(&aph, vcc->vcc.vci);
524117632Sharti
525147256Sbrooks	atm_input(sc->ifp, &aph, m, vcc->rxhand);
526117632Sharti}
527