diff options
Diffstat (limited to 'sys/gnu/isdn/if_ii.c')
-rw-r--r-- | sys/gnu/isdn/if_ii.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/sys/gnu/isdn/if_ii.c b/sys/gnu/isdn/if_ii.c new file mode 100644 index 0000000..c02657e --- /dev/null +++ b/sys/gnu/isdn/if_ii.c @@ -0,0 +1,245 @@ +static char _if_iiid[] = "@(#)$Id: if_ii.c,v 1.1 1995/01/25 14:06:18 jkr Exp jkr $"; +/******************************************************************************* + * II - Version 0.1 $Revision: 1.1 $ $State: Exp $ + * + * Copyright 1994 Dietmar Friede + ******************************************************************************* + * Bug reports, patches, comments, suggestions should be sent to: + * + * jkr@saarlink.de or jkrause@guug.de + * + ******************************************************************************* + * $Log: if_ii.c,v $ + * + ******************************************************************************/ + +/* + * Copyright (c) 1994 Dietmar Friede (dietmar@friede.de) All rights reserved. + * FSF/FSAG GNU Copyright applies + * + * A high level ip isdn driver. + * + * Uses loop driver as template. Small - and simple - is beautiful. + */ + +#include "param.h" +#include "systm.h" +#include "mbuf.h" +#include "socket.h" +#include "errno.h" +#include "ioctl.h" +#include "protosw.h" + +#include "net/if.h" +#include "net/if_types.h" +#include "net/netisr.h" +#include "net/route.h" + +#ifdef INET +#include "netinet/in.h" +#include "netinet/in_systm.h" +#include "netinet/in_var.h" +#include "netinet/ip.h" +#endif + +#include "ii.h" +#include "isdn/isdn_ioctl.h" + +#define IIMTU 1500 + +static struct ifnet ii_if[NII]; +static int applnr[NII]; +static int next_if = 0; +int iioutput(), ii_ioctl(); + +int +iiattach(int ap) +{ + register struct ifnet *ifp; + + if (next_if >= NII) + return -1; + + applnr[next_if] = ap; + ifp = &ii_if[next_if]; + ifp->if_unit = next_if; + ifp->if_name = "ii"; + ifp->if_mtu = IIMTU; + ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT ; + ifp->if_ioctl = ii_ioctl; + ifp->if_output = iioutput; + ifp->if_type = IFT_ISDNBASIC; + ifp->if_hdrlen = 0; + ifp->if_addrlen = 0; + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + if_attach(ifp); + /* ifp->if_flags |= IFF_RUNNING; */ + return next_if++; +} + +int +iioutput(struct ifnet * ifp, struct mbuf * m, struct sockaddr * dst) +{ + int s, isr; + register struct ifqueue *ifq = 0; + + if (dst->sa_family != AF_INET) + { + m_freem(m); + return EAFNOSUPPORT; + } + s = splhigh(); + if (IF_QFULL(&ifp->if_snd)) + { + IF_DROP(&ifp->if_snd); + m_freem(m); + ifp->if_oerrors++; + isdn_output(applnr[ifp->if_unit]); + splx(s); + return (ENOBUFS); + } + IF_ENQUEUE(&ifp->if_snd, m); + + ifp->if_opackets++; + ifp->if_obytes += m->m_pkthdr.len; + + isdn_output(applnr[ifp->if_unit]); + splx(s); + return (0); +} + +int +ii_input(int no, int len, char *buf) +{ + int error = 0; + struct mbuf *m; + struct ifnet *ifp = &(ii_if[no]); + int s; + + s = splhigh(); + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + { + splx(s); + return (0); + } + + if (len >= MHLEN) + { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) + { + (void) m_free(m); + splx(s); + return (0); + } + } + bcopy((caddr_t) buf, mtod(m, caddr_t), len); + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = len; + m->m_len = len; + + if (IF_QFULL(&ipintrq)) + { + IF_DROP(&ipintrq); + ifp->if_ierrors++; + m_freem(m); + splx(s); + return(0); + } + IF_ENQUEUE(&ipintrq, m); + ifp->if_ipackets++; + schednetisr(NETISR_IP); + splx(s); + return(len); +} + +int +ii_connect(int no) +{ + struct ifnet *ifp = &ii_if[no]; + ifp->if_flags |= IFF_RUNNING; +} + +int +ii_disconnect(int no) +{ + struct ifnet *ifp = &ii_if[no]; + ifp->if_flags &= ~IFF_RUNNING; +} + +int +ii_out(int no, char *buf, int len) +{ + struct ifnet *ifp = &ii_if[no]; + struct mbuf *m0, *m; + int l; + + IF_DEQUEUE(&ifp->if_snd, m); + if (m == 0) + { + return (0); + } + /* + * Copy the mbuf chain into the transmit buf + */ + l = 0; + for (m0 = m; m != 0; m = m->m_next) + { + if((l+= m->m_len) > len) + { + m_freem(m0); + return(0); + } + bcopy(mtod(m, caddr_t), buf, m->m_len); + buf += m->m_len; + } + m_freem(m0); + + return (l); +} + +/* + * Process an ioctl request. + */ +int +ii_ioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + struct ifaddr *ifa = (struct ifaddr *) data; + struct ifreq *ifr = (struct ifreq *) data; + int s; + + switch (cmd) + { + case SIOCSIFDSTADDR: + case SIOCAIFADDR: + case SIOCSIFADDR: + if (ifa->ifa_addr->sa_family != AF_INET) + return(EAFNOSUPPORT); + ifp->if_flags |= IFF_UP; + /* FALLTHROUGH */ + case SIOCSIFFLAGS: + s= splhigh(); + if((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) + { + isdn_disconnect(applnr[ifp->if_unit],0); + ifp->if_flags &= ~IFF_RUNNING; + } + break; + case SIOCSIFMTU: + ifr->ifr_metric = ifp->if_mtu; + break; + case SIOCGIFMTU: + if(ifr->ifr_metric < 2048) + return(EAFNOSUPPORT); + ifp->if_mtu = ifr->ifr_metric; + break; + default: +printf("IIO %x",cmd); + return(EINVAL); + } + return(0); +} |