summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_san_obsd.c
diff options
context:
space:
mode:
authorAlex Feldman <alex@cvs.openbsd.org>2004-06-26 06:42:34 +0000
committerAlex Feldman <alex@cvs.openbsd.org>2004-06-26 06:42:34 +0000
commitef30e9ded064276643aa397a8ebf9264045b7d18 (patch)
treebcd74bdff94e669caddb50d42fddbcaf76832eaf /sys/dev/pci/if_san_obsd.c
parent749c2277f90ee646890cd949efcaa998dbc6fb69 (diff)
Sangoma Network Device driver for AFT series card (initiali version).
ok mcbride@
Diffstat (limited to 'sys/dev/pci/if_san_obsd.c')
-rw-r--r--sys/dev/pci/if_san_obsd.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/sys/dev/pci/if_san_obsd.c b/sys/dev/pci/if_san_obsd.c
new file mode 100644
index 00000000000..1744a275ddf
--- /dev/null
+++ b/sys/dev/pci/if_san_obsd.c
@@ -0,0 +1,393 @@
+/*-
+ * Copyright (c) 2001-2004 Sangoma Technologies (SAN)
+ * All rights reserved. www.sangoma.com
+ *
+ * This code is written by Alex Feldman <al.feldman@sangoma.com> for SAN.
+ *
+ * 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.
+ * 3. Neither the name of Sangoma Technologies nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SANGOMA TECHNOLOGIES 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 FOUNDATION 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.
+ */
+
+# include </usr/include/bitstring.h>
+# include <sys/types.h>
+# include <sys/param.h>
+# include <sys/systm.h>
+# include <sys/syslog.h>
+# include <sys/ioccom.h>
+# include <sys/conf.h>
+# include <sys/malloc.h>
+# include <sys/errno.h>
+# include <sys/exec.h>
+# include <sys/mbuf.h>
+# include <sys/sockio.h>
+# include <sys/socket.h>
+# include <sys/kernel.h>
+# include <sys/device.h>
+# include <sys/time.h>
+# include <sys/timeout.h>
+
+# include <net/if.h>
+# include <net/if_media.h>
+# include <net/netisr.h>
+# include <net/if_sppp.h>
+# include <netinet/in_systm.h>
+# include <netinet/in.h>
+
+# include <netinet/udp.h>
+# include <netinet/ip.h>
+
+#include <dev/pci/if_san_common.h>
+#include <dev/pci/if_san_obsd.h>
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef _DEBUG_
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+/****** Function Prototypes *************************************************/
+
+static sdla_t* wanpipe_generic_getcard(struct ifnet*);
+static int wanpipe_generic_ioctl(struct ifnet*, u_long, caddr_t);
+static void wanpipe_generic_watchdog(struct ifnet*);
+static void wanpipe_generic_start(struct ifnet*);
+
+/****** Global Data **********************************************************
+ * Note: All data must be explicitly initialized!!!
+ */
+static char* san_ifname_format = "san%d";
+
+/******* WAN Device Driver Entry Points *************************************/
+static sdla_t* wanpipe_generic_getcard(struct ifnet* ifp)
+{
+ sdla_t* card;
+
+ if (ifp->if_softc == NULL){
+ log(LOG_INFO, "%s: Invalid device private structure pointer\n",
+ ifp->if_xname);
+ return NULL;
+ }
+ card = ((sdla_t*)((wanpipe_common_t*)ifp->if_softc)->card);
+ if (card == NULL){
+ log(LOG_INFO, "%s: Invalid Sangoma device card\n",
+ ifp->if_xname);
+ return NULL;
+ }
+ return card;
+}
+
+int wanpipe_generic_name(sdla_t* card, char* ifname)
+{
+ static int ifunit = 0;
+#if 0
+ char if_name[IFNAMSIZ+1];
+
+ snprintf(if_name, strlen(if_name), ifname_format, ifunit++);
+ bcopy(if_name, ifname, strlen(if_name));
+#endif
+ snprintf(ifname, IFNAMSIZ+1, san_ifname_format, ifunit++);
+ return 0;
+}
+
+int wanpipe_generic_register (sdla_t* card, struct ifnet* ifp, char *ifname)
+{
+ if (ifname == NULL || strlen(ifname) > IFNAMSIZ){
+ return -EINVAL;
+ }else{
+ bcopy(ifname, ifp->if_xname, strlen(ifname));
+ }
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ ifp->if_mtu = PP_MTU;
+ ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+ ((struct sppp *)ifp)->pp_flags |= PP_CISCO;
+ ((struct sppp *)ifp)->pp_flags |= PP_KEEPALIVE;
+ ifp->if_ioctl = wanpipe_generic_ioctl; /* Will set from new_if() */
+ ifp->if_start = wanpipe_generic_start;
+ ifp->if_watchdog = wanpipe_generic_watchdog;
+
+ if_attach(ifp);
+ if_alloc_sadl(ifp);
+ sppp_attach(ifp);
+#if defined(NBPFILTER)
+ bpfattach(&ifp->if_bpf, ifp, DLT_NULL, 4);
+#endif
+ return 0;
+}
+
+void wanpipe_generic_unregister (struct ifnet* ifp)
+{
+ log(LOG_INFO, "%s: Unregister interface!\n",
+ ifp->if_xname);
+ sppp_detach(ifp);
+ if_free_sadl(ifp);
+ if_detach(ifp);
+}
+
+
+static void wanpipe_generic_start(struct ifnet* ifp)
+{
+ sdla_t* card;
+ struct mbuf *opkt;
+ int err = 0;
+#if defined(NBPFILTER)
+ struct mbuf m0;
+ u_int32_t af = AF_INET;
+#endif
+
+ if ((card = wanpipe_generic_getcard(ifp)) == NULL){
+ return;
+ }
+ while (1){
+ if (sppp_isempty(ifp)){
+ /* No more packets in send queue */
+ break;
+ }
+
+ if ((opkt = sppp_dequeue(ifp)) == NULL){
+ /* Should never happened, packet pointer is NULL */
+ break;
+ }
+ if (card->iface_send == NULL){
+ m_freem(opkt);
+ break;
+ }
+ /* report the packet to BPF if present and attached */
+#if defined(NBPFILTER)
+ if (ifp->if_bpf){
+ m0.m_next = opkt;
+ m0.m_len = 4;
+ m0.m_data = (char*)&af;
+ bpf_mtap(ifp->if_bpf, &m0);
+ }
+#endif
+
+ err = card->iface_send(opkt, ifp);
+ if (err){
+ break;
+ }
+ }
+ return;
+}
+
+
+static int wanpipe_generic_ioctl(struct ifnet* ifp, u_long cmd, caddr_t data)
+{
+ struct ifreq *ifr = (struct ifreq*)data;
+ sdla_t *card;
+ wanpipe_common_t* common = WAN_IFP_TO_COMMON(ifp);
+ struct if_settings ifsettings;
+ unsigned long ts_map;
+ int err = 0, s;
+
+ if ((card = wanpipe_generic_getcard(ifp)) == NULL){
+ return -EINVAL;
+ }
+ s = splnet();
+ switch (cmd){
+ case SIOCSIFADDR:
+ err = 1;
+ break;
+
+ case SIOCSIFMEDIA:
+ /* You can't set new media type while card is running */
+ if (card->state != WAN_DISCONNECTED){
+ log(LOG_INFO, "%s: Unable to change media type!\n",
+ ifp->if_xname);
+ err = -EINVAL;
+ goto ioctl_out;
+ }
+ err = ifmedia_ioctl(ifp, ifr, &common->ifm, cmd);
+ break;
+
+ case SIOCGIFMEDIA:
+ err = ifmedia_ioctl(ifp, ifr, &common->ifm, cmd);
+ break;
+
+ case SIOCSIFTIMESLOT:
+ if (card->state != WAN_DISCONNECTED){
+ log(LOG_INFO, "%s: Unable to change timeslot map!\n",
+ ifp->if_xname);
+ err = -EINVAL;
+ goto ioctl_out;
+ }
+ err = copyin(ifr->ifr_data, &ts_map, sizeof(ts_map));
+ if (err)
+ goto ioctl_out;
+ sdla_te_settimeslot(card, ts_map);
+ break;
+
+ case SIOCGIFTIMESLOT:
+ ts_map = sdla_te_gettimeslot(card);
+ err = copyout(ifr->ifr_data, &ts_map, sizeof(ts_map));
+ if (err)
+ goto ioctl_out;
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ ** If the interface is marked up - enable communications.
+ ** If down - disable communications. IFF_UP is taken
+ ** care of before entering this function.
+ */
+ if ((ifp->if_flags & IFF_UP) == 0){
+ /* bring it down */
+ log(LOG_INFO, "%s: Bringing interface down.\n",
+ ifp->if_xname);
+ if (card->iface_down){
+ card->iface_down(ifp);
+ }
+ }else{ /* bring it up */
+ log(LOG_INFO, "%s: Bringing interface up.\n",
+ ifp->if_xname);
+ if (card->iface_up){
+ card->iface_up(ifp);
+ }
+ wanpipe_generic_start(ifp);
+ }
+ break;
+
+ case SIOC_WANPIPE_DEVICE:
+ err = copyin(ifr->ifr_data,
+ &ifsettings,
+ sizeof(struct if_settings));
+ if (err){
+ log(LOG_INFO, "%s: Failed to copy from user space!\n",
+ card->devname);
+ goto ioctl_out;
+ }
+ switch (ifsettings.type){
+ case IF_GET_PROTO:
+ ifsettings.type = common->protocol;
+ err = copyout(&ifsettings,
+ ifr->ifr_data,
+ sizeof(struct if_settings));
+ if (err){
+ log(LOG_INFO, "%s: Failed to copy to uspace!\n",
+ card->devname);
+ }
+ break;
+
+ case IF_PROTO_CISCO:
+ case IF_PROTO_PPP:
+ err = wp_lite_set_proto(ifp, (struct ifreq*)data);
+ break;
+
+ default:
+ if (card->iface_ioctl){
+ err = card->iface_ioctl(
+ ifp,
+ cmd,
+ (struct ifreq*)data);
+ }
+ break;
+ }
+ break;
+
+ default:
+ if (card->iface_ioctl){
+ /* Argument seqeunce is change for Linux order */
+ err = card->iface_ioctl(ifp, cmd, (struct ifreq*)data);
+ }
+ break;
+ }
+
+ if (err){
+ err = sppp_ioctl(ifp, cmd, data);
+ }
+ioctl_out:
+ splx(s);
+ return err;
+}
+
+static void wanpipe_generic_watchdog(struct ifnet* ifp)
+{
+ return;
+}
+
+int wanpipe_generic_open(struct ifnet* ifp)
+{
+ return 0;
+}
+
+int wanpipe_generic_close(struct ifnet* ifp)
+{
+ return 0;
+}
+
+int wanpipe_generic_input(struct ifnet* ifp, struct mbuf* m)
+{
+ sdla_t *card;
+#if defined(NBPFILTER)
+ struct mbuf m0;
+ u_int32_t af = AF_INET;
+#endif
+
+ if ((card = wanpipe_generic_getcard(ifp)) == NULL){
+ return -EINVAL;
+ }
+ m->m_pkthdr.rcvif = ifp;
+#if defined(NBPFILTER)
+ if (ifp->if_bpf){
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char*)&af;
+ bpf_mtap(ifp->if_bpf, &m0);
+ }
+#endif
+ ifp->if_ipackets ++;
+ ifp->if_ibytes += m->m_len;
+ sppp_input(ifp, m);
+ return 0;
+}
+
+int wp_lite_set_proto(struct ifnet* ifp, struct ifreq* ifr)
+{
+ wanpipe_common_t* common;
+ struct if_settings* ifsettings;
+ int err = 0;
+
+ if ((common = ifp->if_softc) == NULL){
+ log(LOG_INFO, "%s: Private structure is null!\n",
+ ifp->if_xname);
+ return -EINVAL;
+ }
+ ifsettings = (struct if_settings*)ifr->ifr_data;
+ switch (ifsettings->type) {
+ case IF_PROTO_CISCO:
+ ((struct sppp *)ifp)->pp_flags |= PP_CISCO;
+ ((struct sppp *)ifp)->pp_flags |= PP_KEEPALIVE;
+ break;
+ case IF_PROTO_PPP:
+ ((struct sppp *)ifp)->pp_flags &= ~PP_CISCO;
+ ((struct sppp *)ifp)->pp_flags &= ~PP_KEEPALIVE;
+ break;
+ }
+ err = sppp_ioctl(ifp, SIOCSIFFLAGS, ifr);
+ return err;
+}
+
+/************************************ END **********************************/