3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * Author: Harti Brandt <harti@freebsd.org>
29 * HARP pseudo-driver. This driver when loaded attaches to all ngATM drivers
30 * in the system and creates a HARP physical interface for each of them.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/queue.h>
46 #include <sys/syslog.h>
48 #include <sys/sockio.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
54 #include <net/if_var.h>
55 #include <net/if_types.h>
56 #include <net/if_media.h>
57 #include <net/netisr.h>
59 #include <netatm/port.h>
60 #include <netatm/queue.h>
61 #include <netatm/atm.h>
62 #include <netatm/atm_sys.h>
63 #include <netatm/atm_sap.h>
64 #include <netatm/atm_cm.h>
65 #include <netatm/atm_if.h>
66 #include <netatm/atm_stack.h>
67 #include <netatm/atm_pcb.h>
68 #include <netatm/atm_var.h>
69 #include <netatm/atm_vc.h>
71 #include <net/if_atm.h>
76 * Physical interface softc
81 LIST_ENTRY(harp_softc) link;
88 MODULE_VERSION(harp, 1);
89 MODULE_DEPEND(harp, atm, 1, 1, 1);
91 /* hooks from if_atmsubr.c */
92 extern void (*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m,
93 struct atm_pseudohdr *ah, void *rxhand);
94 extern void (*atm_harp_attach_p)(struct ifnet *);
95 extern void (*atm_harp_detach_p)(struct ifnet *);
97 static MALLOC_DEFINE(M_HARP, "harp", "Harp pseudo interface");
99 static uma_zone_t harp_nif_zone;
100 static uma_zone_t harp_vcc_zone;
102 /* List of all existing 'harp' interfaces */
103 static LIST_HEAD(, harp_softc) harp_softc_list =
104 LIST_HEAD_INITIALIZER(harp_softc_list);
106 static struct stack_defn harp_svaal5 = {
116 static struct stack_defn *harp_services = &harp_svaal5;
119 * Map between constants
121 static const struct {
126 [ATM_DEVICE_UNKNOWN] =
127 { VENDOR_UNKNOWN, VENDAPI_UNKNOWN, DEV_UNKNOWN },
128 [ATM_DEVICE_PCA200E] =
129 { VENDOR_FORE, VENDAPI_FORE_1, DEV_FORE_PCA200E },
131 { VENDOR_FORE, VENDAPI_FORE_2, DEV_FORE_HE155 },
133 { VENDOR_FORE, VENDAPI_FORE_2, DEV_FORE_HE622 },
134 [ATM_DEVICE_ENI155P] =
135 { VENDOR_ENI, VENDAPI_ENI_1, DEV_ENI_155P },
136 [ATM_DEVICE_ADP155P] =
137 { VENDOR_ENI, VENDAPI_ENI_1, DEV_ENI_155P },
138 [ATM_DEVICE_FORELE25] =
139 { VENDOR_FORE, VENDAPI_IDT_1, DEV_FORE_LE25 },
140 [ATM_DEVICE_FORELE155] =
141 { VENDOR_FORE, VENDAPI_IDT_1, DEV_FORE_LE155 },
142 [ATM_DEVICE_NICSTAR25] =
143 { VENDOR_IDT, VENDAPI_IDT_1, DEV_IDT_25 },
144 [ATM_DEVICE_NICSTAR155] =
145 { VENDOR_IDT, VENDAPI_IDT_1, DEV_IDT_155 },
146 [ATM_DEVICE_IDTABR25] =
147 { VENDOR_IDT, VENDAPI_IDT_2, DEV_IDTABR_25 },
148 [ATM_DEVICE_IDTABR155] =
149 { VENDOR_IDT, VENDAPI_IDT_2, DEV_IDTABR_155 },
150 [ATM_DEVICE_PROATM25] =
151 { VENDOR_PROSUM, VENDAPI_IDT_2, DEV_PROATM_25 },
152 [ATM_DEVICE_PROATM155] =
153 { VENDOR_PROSUM, VENDAPI_IDT_2, DEV_PROATM_155 },
157 * Return zero if this interface is ok for us.
158 * XXX This should go away when we have full ngATM-ified the en driver.
161 harp_check_if(const struct ifnet *ifp)
163 if (ifp->if_type == IFT_ATM && strcmp(ifp->if_dname, "en"))
170 * Instantiate a VCC stack.
172 * Could check for correct attributes here.
175 harp_instvcc(Cmn_unit *up, Cmn_vcc *vp)
177 struct harp_softc *sc;
179 if (up == NULL || vp == NULL || vp->cv_connvc == NULL)
182 sc = (struct harp_softc *)up;
191 harp_openvcc(Cmn_unit *up, Cmn_vcc *vp)
193 struct harp_softc *sc;
194 struct atmio_openvcc data;
195 Atm_attributes *attrib;
197 const struct ifatm_mib *mib;
200 if (up == NULL || vp == NULL || vp->cv_connvc == NULL)
203 sc = (struct harp_softc *)up;
204 mib = sc->parent->if_linkmib;
206 attrib = &vp->cv_connvc->cvc_attr;
207 vccinf = vp->cv_connvc->cvc_vcc;
209 if (attrib == NULL || vccinf == NULL)
212 if (vccinf->vc_vpi >= (1 << mib->vpi_bits) ||
213 vccinf->vc_vci >= (1 << mib->vci_bits))
216 memset(&data, 0, sizeof(data));
218 switch (attrib->aal.type) {
221 data.param.aal = ATMIO_AAL_0;
225 data.param.aal = ATMIO_AAL_5;
231 data.param.vpi = vccinf->vc_vpi;
232 data.param.vci = vccinf->vc_vci;
233 data.param.rmtu = HARP_MTU;
234 data.param.tmtu = HARP_MTU;
236 switch (attrib->bearer.v.bearer_class) {
239 data.param.traffic = ATMIO_TRAFFIC_VBR;
243 switch (attrib->bearer.v.traffic_type) {
246 data.param.traffic = ATMIO_TRAFFIC_CBR;
250 data.param.traffic = ATMIO_TRAFFIC_VBR;
254 /* not really supported by HARP */
259 data.param.traffic = ATMIO_TRAFFIC_UBR;
267 data.param.tparam.pcr = attrib->traffic.v.forward.PCR_all_traffic;
268 data.param.tparam.scr = attrib->traffic.v.forward.SCR_all_traffic;
269 data.param.tparam.mbs = attrib->traffic.v.forward.MBS_all_traffic;
272 data.param.flags = ATMIO_FLAG_HARP;
274 err = (*sc->parent->if_ioctl)(sc->parent, SIOCATMOPENVCC,
284 harp_closevcc(Cmn_unit *up, Cmn_vcc *vp)
286 struct harp_softc *sc;
287 struct atmio_closevcc data;
290 if (vp == NULL || vp->cv_connvc == NULL ||
291 vp->cv_connvc->cvc_vcc == NULL)
294 sc = (struct harp_softc *)up;
296 data.vpi = vp->cv_connvc->cvc_vcc->vc_vpi;
297 data.vci = vp->cv_connvc->cvc_vcc->vc_vci;
299 err = (*sc->parent->if_ioctl)(sc->parent, SIOCATMCLOSEVCC,
309 harp_ioctl(int code, caddr_t addr, caddr_t arg)
318 harp_output(Cmn_unit *cu, Cmn_vcc *cv, KBuffer *m)
320 struct harp_softc *sc = (struct harp_softc *)cu;
321 struct atm_pseudohdr *aph;
325 if (cv == NULL || cv->cv_connvc == NULL ||
326 cv->cv_connvc->cvc_vcc == NULL) {
333 * Harp seems very broken with regard to mbuf handling. The length
334 * in the packet header is mostly broken here so recompute it.
336 m->m_pkthdr.len = mlen = m_length(m, NULL);
339 * Prepend pseudo-hdr. Drivers don't care about the flags.
341 M_PREPEND(m, sizeof(*aph), M_DONTWAIT);
345 aph = mtod(m, struct atm_pseudohdr *);
346 ATM_PH_VPI(aph) = cv->cv_connvc->cvc_vcc->vc_vpi;
347 ATM_PH_SETVCI(aph, cv->cv_connvc->cvc_vcc->vc_vci);
348 ATM_PH_FLAGS(aph) = 0;
350 error = atm_output(sc->parent, m, NULL, NULL);
353 printf("%s: error %d\n", __func__, error);
354 sc->cmn.cu_pif.pif_oerrors++;
355 cv->cv_connvc->cvc_vcc->vc_oerrors++;
356 if (cv->cv_connvc->cvc_vcc->vc_nif)
357 cv->cv_connvc->cvc_vcc->vc_nif->nif_if.if_oerrors++;
362 sc->cmn.cu_pif.pif_opdus++;
363 sc->cmn.cu_pif.pif_obytes += mlen;
364 cv->cv_connvc->cvc_vcc->vc_opdus++;
365 cv->cv_connvc->cvc_vcc->vc_obytes += mlen;
366 if (cv->cv_connvc->cvc_vcc->vc_nif) {
367 cv->cv_connvc->cvc_vcc->vc_nif->nif_obytes += mlen;
368 cv->cv_connvc->cvc_vcc->vc_nif->nif_if.if_obytes += mlen;
369 cv->cv_connvc->cvc_vcc->vc_nif->nif_if.if_opackets++;
374 * Attach a new interface
377 harp_attach(struct ifnet *parent)
379 struct harp_softc *sc;
380 const struct ifatm_mib *mib;
383 if (harp_check_if(parent) != 0)
386 sc = malloc(sizeof(*sc), M_HARP, M_WAITOK | M_ZERO);
389 sc->cmn.cu_unit = parent->if_dunit;
390 sc->cmn.cu_mtu = HARP_MTU;
391 sc->cmn.cu_ioctl = harp_ioctl;
392 sc->cmn.cu_instvcc = harp_instvcc;
393 sc->cmn.cu_openvcc = harp_openvcc;
394 sc->cmn.cu_closevcc = harp_closevcc;
395 sc->cmn.cu_output = harp_output;
396 sc->cmn.cu_vcc_zone = harp_vcc_zone;
397 sc->cmn.cu_nif_zone = harp_nif_zone;
398 sc->cmn.cu_softc = sc;
401 mib = parent->if_linkmib;
402 if (mib->device >= sizeof(map_devs) / sizeof(map_devs[0])) {
403 sc->cmn.cu_config.ac_vendor = VENDOR_UNKNOWN;
404 sc->cmn.cu_config.ac_vendapi = VENDAPI_UNKNOWN;
405 sc->cmn.cu_config.ac_device = DEV_UNKNOWN;
407 sc->cmn.cu_config.ac_vendor = map_devs[mib->device].vendor;
408 sc->cmn.cu_config.ac_vendapi = map_devs[mib->device].api;
409 sc->cmn.cu_config.ac_device = map_devs[mib->device].dev;
412 switch (mib->media) {
415 sc->cmn.cu_config.ac_media = MEDIA_UTP25;;
418 case IFM_ATM_TAXI_100:
419 sc->cmn.cu_config.ac_media = MEDIA_TAXI_100;
422 case IFM_ATM_TAXI_140:
423 sc->cmn.cu_config.ac_media = MEDIA_TAXI_140;
428 sc->cmn.cu_config.ac_media = MEDIA_OC3C;
433 sc->cmn.cu_config.ac_media = MEDIA_OC12C;
436 case IFM_ATM_UTP_155:
437 sc->cmn.cu_config.ac_media = MEDIA_UTP155;
441 sc->cmn.cu_config.ac_media = MEDIA_UNKNOWN;
444 sc->cmn.cu_config.ac_bustype = BUS_PCI;
445 sc->cmn.cu_pif.pif_pcr = mib->pcr;
446 sc->cmn.cu_pif.pif_maxvpi = (1 << mib->vpi_bits) - 1;
447 sc->cmn.cu_pif.pif_maxvci = (1 << mib->vci_bits) - 1;
449 snprintf(sc->cmn.cu_config.ac_hard_vers,
450 sizeof(sc->cmn.cu_config.ac_hard_vers), "0x%lx",
451 (u_long)mib->hw_version);
452 snprintf(sc->cmn.cu_config.ac_firm_vers,
453 sizeof(sc->cmn.cu_config.ac_firm_vers), "0x%lx",
454 (u_long)mib->sw_version);
455 sc->cmn.cu_config.ac_serial = mib->serial;
456 sc->cmn.cu_config.ac_ram = 0;
457 sc->cmn.cu_config.ac_ramsize = 0;
459 sc->cmn.cu_config.ac_macaddr.ma_data[0] =
460 sc->cmn.cu_pif.pif_macaddr.ma_data[0] = mib->esi[0];
461 sc->cmn.cu_config.ac_macaddr.ma_data[1] =
462 sc->cmn.cu_pif.pif_macaddr.ma_data[1] = mib->esi[1];
463 sc->cmn.cu_config.ac_macaddr.ma_data[2] =
464 sc->cmn.cu_pif.pif_macaddr.ma_data[2] = mib->esi[2];
465 sc->cmn.cu_config.ac_macaddr.ma_data[3] =
466 sc->cmn.cu_pif.pif_macaddr.ma_data[3] = mib->esi[3];
467 sc->cmn.cu_config.ac_macaddr.ma_data[4] =
468 sc->cmn.cu_pif.pif_macaddr.ma_data[4] = mib->esi[4];
469 sc->cmn.cu_config.ac_macaddr.ma_data[5] =
470 sc->cmn.cu_pif.pif_macaddr.ma_data[5] = mib->esi[5];
472 error = atm_physif_register(&sc->cmn, parent->if_dname, harp_services);
474 log(LOG_ERR, "%s: pif registration failed %d\n",
475 parent->if_dname, error);
479 LIST_INSERT_HEAD(&harp_softc_list, sc, link);
481 sc->cmn.cu_flags |= CUF_INITED;
485 * Destroy a cloned device
488 harp_detach(struct ifnet *ifp)
490 struct harp_softc *sc;
493 LIST_FOREACH(sc, &harp_softc_list, link)
494 if (sc->parent == ifp)
499 error = atm_physif_deregister(&sc->cmn);
501 log(LOG_ERR, "%s: de-registration failed %d\n", ifp->if_dname,
504 LIST_REMOVE(sc, link);
510 * Pass PDU up the stack
513 harp_recv_stack(void *tok, KBuffer *m)
519 STACK_CALL(CPCS_UNITDATA_SIG, vcc->cv_upper, vcc->cv_toku,
520 vcc->cv_connvc, (intptr_t)m, 0, err);
522 printf("%s: error %d\n", __func__, err);
528 * Possible input from NATM
531 harp_input(struct ifnet *ifp, struct mbuf **mp, struct atm_pseudohdr *ah,
534 struct harp_softc *sc = rxhand;
541 if ((ATM_PH_FLAGS(ah) & ATMIO_FLAG_HARP) == 0)
544 /* grab the packet */
548 if (sc->parent != ifp) {
549 printf("%s: parent=%p ifp=%p\n", __func__, sc->parent, ifp);
553 vcc = atm_dev_vcc_find(&sc->cmn, ATM_PH_VPI(ah),
554 ATM_PH_VCI(ah), VCC_IN);
556 printf("%s: VCC %u/%u not found\n", __func__,ATM_PH_VPI(ah),
561 /* fit two pointers into the mbuf - assume, that the the data is
562 * pointer aligned. If it doesn't fit into the first mbuf, prepend
564 * Don't count the new fields in the packet length (XXX)
566 mlen = m->m_pkthdr.len;
567 pfxlen = sizeof(atm_intr_func_t) + sizeof(void *);
568 if (M_LEADINGSPACE(m) < pfxlen) {
569 MGETHDR(m0, 0, MT_DATA);
571 printf("%s: no leading space in buffer\n", __func__);
577 M_MOVE_PKTHDR(m0, m);
583 cp = mtod(m, char *);
584 *((atm_intr_func_t *)cp) = harp_recv_stack;
585 cp += sizeof(atm_intr_func_t);
586 *((void **)cp) = (void *)vcc;
588 /* count the packet */
589 sc->cmn.cu_pif.pif_ipdus++;
590 sc->cmn.cu_pif.pif_ibytes += mlen;
591 vcc->cv_connvc->cvc_vcc->vc_ipdus++;
592 vcc->cv_connvc->cvc_vcc->vc_ibytes += mlen;
593 if (vcc->cv_connvc->cvc_vcc->vc_nif) {
594 vcc->cv_connvc->cvc_vcc->vc_nif->nif_ibytes += mlen;
595 vcc->cv_connvc->cvc_vcc->vc_nif->nif_if.if_ipackets++;
596 vcc->cv_connvc->cvc_vcc->vc_nif->nif_if.if_ibytes += mlen;
600 netisr_dispatch(NETISR_ATM, m);
608 * Module loading/unloading
611 harp_modevent(module_t mod, int event, void *data)
618 harp_nif_zone = uma_zcreate("harp nif", sizeof(struct atm_nif),
619 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
620 if (harp_nif_zone == NULL)
621 panic("%s: nif_zone", __func__);
623 harp_vcc_zone = uma_zcreate("harp vcc", sizeof(struct harp_vcc),
624 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
625 if (harp_vcc_zone == NULL)
626 panic("%s: vcc_zone", __func__);
628 /* Create harp interfaces for all existing ATM interfaces */
629 TAILQ_FOREACH(ifp, &ifnet, if_link)
632 atm_harp_attach_p = harp_attach;
633 atm_harp_detach_p = harp_detach;
634 atm_harp_input_p = harp_input;
638 atm_harp_attach_p = NULL;
639 atm_harp_detach_p = NULL;
640 atm_harp_input_p = NULL;
642 while (!LIST_EMPTY(&harp_softc_list))
643 harp_detach(LIST_FIRST(&harp_softc_list)->parent);
645 uma_zdestroy(harp_nif_zone);
646 uma_zdestroy(harp_vcc_zone);
655 static moduledata_t harp_mod = {
661 DECLARE_MODULE(harp, harp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);