summaryrefslogtreecommitdiffstats
path: root/sys/dev/patm/if_patm_ioctl.c
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-07-15 11:57:24 +0000
committerharti <harti@FreeBSD.org>2003-07-15 11:57:24 +0000
commit0d78becf4af9282a5db1755207cdcbd574978b82 (patch)
tree44442f21b1cfa8eb3a2a600b9254c9f26a4d4a39 /sys/dev/patm/if_patm_ioctl.c
parent44a5a052691f26ac154bd497d1c19f85dcf7f96c (diff)
downloadFreeBSD-src-0d78becf4af9282a5db1755207cdcbd574978b82.zip
FreeBSD-src-0d78becf4af9282a5db1755207cdcbd574978b82.tar.gz
This is a driver for IDT77252 based ATM interfaces. It has been tested
with a ProATM-155 and an IDT evaluation board and should also work with a ProATM-25 (it seems to work at least, I cannot really measure what the card emits). The driver has been tested on i386 and sparc64, but should work an other archs also. It supports UBR, CBR, ABR and VBR; AAL0, AAL5 and AALraw. As an additional feature VCI/VPI 0/0 can be opened for receiving in AALraw mode and receives all cells not claimed by other open VCs (even cells with invalid GFC, VPI and VCI fields and OAM cells). Thanks to Christian Bucari from ProSum for lending two cards and answering my questions.
Diffstat (limited to 'sys/dev/patm/if_patm_ioctl.c')
-rw-r--r--sys/dev/patm/if_patm_ioctl.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/sys/dev/patm/if_patm_ioctl.c b/sys/dev/patm/if_patm_ioctl.c
new file mode 100644
index 0000000..c91e714
--- /dev/null
+++ b/sys/dev/patm/if_patm_ioctl.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * Driver for IDT77252 based cards like ProSum's.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet.h"
+#include "opt_natm.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/condvar.h>
+#include <vm/uma.h>
+
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_atm.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_atm.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/mbpool.h>
+
+#include <dev/utopia/utopia.h>
+#include <dev/patm/idt77252reg.h>
+#include <dev/patm/if_patmvar.h>
+
+/*
+ * Open the VCC with the given parameters
+ */
+static int
+patm_open_vcc(struct patm_softc *sc, struct atmio_openvcc *arg, u_int async)
+{
+ u_int cid;
+ struct patm_vcc *vcc;
+ int error = 0;
+
+ patm_debug(sc, VCC, "Open VCC: %u.%u flags=%#x", arg->param.vpi,
+ arg->param.vci, arg->param.flags);
+
+ if (!LEGAL_VPI(sc, arg->param.vpi) || !LEGAL_VCI(sc, arg->param.vci))
+ return (EINVAL);
+ if (arg->param.vci == 0 && (arg->param.vpi != 0 ||
+ !(arg->param.flags & ATMIO_FLAG_NOTX) ||
+ arg->param.aal != ATMIO_AAL_RAW))
+ return (EINVAL);
+ cid = PATM_CID(sc, arg->param.vpi, arg->param.vci);
+
+ if ((arg->param.flags & ATMIO_FLAG_NOTX) &&
+ (arg->param.flags & ATMIO_FLAG_NORX))
+ return (EINVAL);
+
+ if ((arg->param.traffic == ATMIO_TRAFFIC_ABR) &&
+ (arg->param.flags & (ATMIO_FLAG_NOTX | ATMIO_FLAG_NORX)))
+ return (EINVAL);
+
+ /* allocate vcc */
+ vcc = uma_zalloc(sc->vcc_zone, M_NOWAIT | M_ZERO);
+ if (vcc == NULL)
+ return (ENOMEM);
+
+ mtx_lock(&sc->mtx);
+ if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) {
+ /* stopped while we have analyzed the arguments */
+ error = EIO;
+ goto done;
+ }
+ if (sc->vccs[cid] != NULL) {
+ /* ups, already open */
+ error = EBUSY;
+ goto done;
+ }
+
+ /* check some parameters */
+ vcc->cid = cid;
+ vcc->vcc = arg->param;
+ vcc->vflags = async;
+ vcc->rxhand = arg->rxhand;
+ switch (vcc->vcc.aal) {
+
+ case ATMIO_AAL_0:
+ case ATMIO_AAL_34:
+ case ATMIO_AAL_5:
+ break;
+
+ case ATMIO_AAL_RAW:
+ if (arg->param.vci == 0 &&
+ !(arg->param.flags & ATMIO_FLAG_NOTX)) {
+ error = EINVAL;
+ goto done;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ goto done;
+ }
+ switch (vcc->vcc.traffic) {
+
+ case ATMIO_TRAFFIC_VBR:
+ case ATMIO_TRAFFIC_UBR:
+ case ATMIO_TRAFFIC_CBR:
+ case ATMIO_TRAFFIC_ABR:
+ break;
+
+ default:
+ error = EINVAL;
+ goto done;
+ }
+
+ /* initialize */
+ vcc->chain = NULL;
+ vcc->last = NULL;
+ vcc->ibytes = vcc->ipackets = 0;
+ vcc->obytes = vcc->opackets = 0;
+
+ /* ask the TX and RX sides */
+ patm_debug(sc, VCC, "Open VCC: asking Rx/Tx");
+ if (!(vcc->vcc.flags & ATMIO_FLAG_NOTX) &&
+ (error = patm_tx_vcc_can_open(sc, vcc)) != 0)
+ goto done;
+ if (!(vcc->vcc.flags & ATMIO_FLAG_NORX) &&
+ (error = patm_rx_vcc_can_open(sc, vcc)) != 0)
+ goto done;
+
+ /* ok - go ahead */
+ sc->vccs[cid] = vcc;
+
+ patm_debug(sc, VCC, "Open VCC: opening");
+ if (!(vcc->vcc.flags & ATMIO_FLAG_NOTX))
+ patm_tx_vcc_open(sc, vcc);
+ if (!(vcc->vcc.flags & ATMIO_FLAG_NORX))
+ patm_rx_vcc_open(sc, vcc);
+
+#ifdef notyet
+ /* inform management about non-NG and NG-PVCs */
+ if (!(vcc->vcc.flags & ATMIO_FLAG_NG) ||
+ (vcc->vcc.flags & ATMIO_FLAG_PVC))
+ atm_message(&sc->ifatm.ifnet, ATM_MSG_VCC_CHANGED,
+ (1 << 24) | (vcc->vcc.vpi << 16) | vcc->vcc.vci);
+#endif
+
+ patm_debug(sc, VCC, "Open VCC: now open");
+
+ /* don't free below */
+ vcc = NULL;
+
+ sc->vccs_open++;
+
+ /* done */
+ done:
+ mtx_unlock(&sc->mtx);
+ if (vcc != NULL)
+ uma_zfree(sc->vcc_zone, vcc);
+ return (error);
+}
+
+/*
+ * Enable ioctl for NATM. Map to an open ioctl.
+ */
+static int
+patm_open_vcc1(struct patm_softc *sc, struct atm_pseudoioctl *ph)
+{
+ struct atmio_openvcc v;
+
+ bzero(&v, sizeof(v));
+ v.param.flags = ATM_PH_FLAGS(&ph->aph) & (ATM_PH_AAL5 | ATM_PH_LLCSNAP);
+ v.param.vpi = ATM_PH_VPI(&ph->aph);
+ v.param.vci = ATM_PH_VCI(&ph->aph);
+ v.param.aal = (ATM_PH_FLAGS(&ph->aph) & ATM_PH_AAL5)
+ ? ATMIO_AAL_5 : ATMIO_AAL_0;
+ v.param.traffic = ATMIO_TRAFFIC_UBR;;
+ v.param.tparam.pcr = sc->ifatm.mib.pcr;
+ v.rxhand = ph->rxhand;
+
+ return (patm_open_vcc(sc, &v, PATM_VCC_ASYNC));
+}
+
+/*
+ * Try to close the given VCC
+ */
+static int
+patm_close_vcc(struct patm_softc *sc, struct atmio_closevcc *arg)
+{
+ u_int cid;
+ struct patm_vcc *vcc;
+ int error = 0;
+
+ patm_debug(sc, VCC, "Close VCC: %u.%u", arg->vpi, arg->vci);
+
+ if (!LEGAL_VPI(sc, arg->vpi) || !LEGAL_VCI(sc, arg->vci))
+ return (EINVAL);
+ cid = PATM_CID(sc, arg->vpi, arg->vci);
+
+ mtx_lock(&sc->mtx);
+ if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) {
+ /* stopped while we have analyzed the arguments */
+ error = EIO;
+ goto done;
+ }
+
+ vcc = sc->vccs[cid];
+ if (vcc == NULL || !(vcc->vflags & PATM_VCC_OPEN)) {
+ error = ENOENT;
+ goto done;
+ }
+
+ if (vcc->vflags & PATM_VCC_TX_OPEN)
+ patm_tx_vcc_close(sc, vcc);
+ if (vcc->vflags & PATM_VCC_RX_OPEN)
+ patm_rx_vcc_close(sc, vcc);
+
+ if (vcc->vflags & PATM_VCC_ASYNC)
+ goto done;
+
+ while (vcc->vflags & (PATM_VCC_TX_CLOSING | PATM_VCC_RX_CLOSING)) {
+ cv_wait(&sc->vcc_cv, &sc->mtx);
+ if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) {
+ /* ups, has been stopped */
+ error = EIO;
+ goto done;
+ }
+ }
+
+ if (!(vcc->vcc.flags & ATMIO_FLAG_NOTX))
+ patm_tx_vcc_closed(sc, vcc);
+ if (!(vcc->vcc.flags & ATMIO_FLAG_NORX))
+ patm_rx_vcc_closed(sc, vcc);
+
+ patm_vcc_closed(sc, vcc);
+
+ done:
+ mtx_unlock(&sc->mtx);
+
+ return (error);
+}
+
+/*
+ * Close a VCC asynchronuosly
+ */
+static int
+patm_close_vcc1(struct patm_softc *sc, struct atm_pseudoioctl *ph)
+{
+ struct atmio_closevcc v;
+
+ v.vpi = ATM_PH_VPI(&ph->aph);
+ v.vci = ATM_PH_VCI(&ph->aph);
+
+ return (patm_close_vcc(sc, &v));
+}
+
+/*
+ * VCC has been finally closed.
+ */
+void
+patm_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
+{
+
+#ifdef notyet
+ /* inform management about non-NG and NG-PVCs */
+ if (!(vcc->vcc.flags & ATMIO_FLAG_NG) ||
+ (vcc->vcc.flags & ATMIO_FLAG_PVC))
+ atm_message(&sc->ifatm.ifnet, ATM_MSG_VCC_CHANGED,
+ (0 << 24) | (vcc->vcc.vpi << 16) | vcc->vcc.vci);
+#endif
+
+ sc->vccs_open--;
+ sc->vccs[vcc->cid] = NULL;
+ uma_zfree(sc->vcc_zone, vcc);
+}
+
+int
+patm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct patm_softc *sc = ifp->if_softc;
+ int error = 0;
+ uint32_t cfg;
+ struct atmio_vcctable *vtab;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ mtx_lock(&sc->mtx);
+ ifp->if_flags |= IFF_UP;
+ if (!(ifp->if_flags & IFF_RUNNING))
+ patm_initialize(sc);
+ switch (ifa->ifa_addr->sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ case AF_INET6:
+ ifa->ifa_rtrequest = atm_rtrequest;
+ break;
+#endif
+ default:
+ break;
+ }
+ mtx_unlock(&sc->mtx);
+ break;
+
+ case SIOCSIFFLAGS:
+ mtx_lock(&sc->mtx);
+ if (ifp->if_flags & IFF_UP) {
+ if (!(ifp->if_flags & IFF_RUNNING)) {
+ patm_initialize(sc);
+ }
+ } else {
+ if (ifp->if_flags & IFF_RUNNING) {
+ patm_stop(sc);
+ }
+ }
+ mtx_unlock(&sc->mtx);
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);
+
+ /*
+ * We need to toggle unassigned/idle cells ourself because
+ * the 77252 generates null cells for spacing. When switching
+ * null cells of it gets the timing wrong.
+ */
+ mtx_lock(&sc->mtx);
+ if (ifp->if_flags & IFF_RUNNING) {
+ if (sc->utopia.state & UTP_ST_UNASS) {
+ if (!(sc->flags & PATM_UNASS)) {
+ cfg = patm_nor_read(sc, IDT_NOR_CFG);
+ cfg &= ~IDT_CFG_IDLECLP;
+ patm_nor_write(sc, IDT_NOR_CFG, cfg);
+ sc->flags |= PATM_UNASS;
+ }
+ } else {
+ if (sc->flags & PATM_UNASS) {
+ cfg = patm_nor_read(sc, IDT_NOR_CFG);
+ cfg |= IDT_CFG_IDLECLP;
+ patm_nor_write(sc, IDT_NOR_CFG, cfg);
+ sc->flags &= ~PATM_UNASS;
+ }
+ }
+ } else {
+ if (sc->utopia.state & UTP_ST_UNASS)
+ sc->flags |= PATM_UNASS;
+ else
+ sc->flags &= ~PATM_UNASS;
+ }
+ mtx_unlock(&sc->mtx);
+ break;
+
+ case SIOCSIFMTU:
+ /*
+ * Set the interface MTU.
+ */
+ if (ifr->ifr_mtu > ATMMTU)
+ error = EINVAL;
+ else
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+
+ case SIOCATMOPENVCC: /* netgraph/harp internal use */
+ error = patm_open_vcc(sc, (struct atmio_openvcc *)data, 0);
+ break;
+
+ case SIOCATMCLOSEVCC: /* netgraph and HARP internal use */
+ error = patm_close_vcc(sc, (struct atmio_closevcc *)data);
+ break;
+
+ case SIOCATMENA: /* NATM internal use */
+ error = patm_open_vcc1(sc, (struct atm_pseudoioctl *)data);
+ break;
+
+ case SIOCATMDIS: /* NATM internal use */
+ error = patm_close_vcc1(sc, (struct atm_pseudoioctl *)data);
+ break;
+
+ case SIOCATMGVCCS: /* external use */
+ /* return vcc table */
+ vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
+ sc->mmap->max_conn, sc->vccs_open, &sc->mtx, 1);
+ error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) +
+ vtab->count * sizeof(vtab->vccs[0]));
+ free(vtab, M_DEVBUF);
+ break;
+
+ case SIOCATMGETVCCS: /* netgraph internal use */
+ vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
+ sc->mmap->max_conn, sc->vccs_open, &sc->mtx, 0);
+ if (vtab == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ *(void **)data = vtab;
+ break;
+
+ default:
+ patm_debug(sc, IOCTL, "unknown cmd=%08lx arg=%p", cmd, data);
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
OpenPOWER on IntegriCloud