home *** CD-ROM | disk | FTP | other *** search
- /*
- * Streams IP network module. SunOS 4.1.
- *
- * Copyright CSIRO Division of Mathematics and Statistics 21 June 1990
- *
- * Author: Mark Andrews, marka@syd.dms.csiro.au
- *
- * Permission is hereby granted for this code to be distributed
- * free of charge with this copyright intact. Derived works should
- * be marked as so.
- */
-
- #include "slip.h"
- #if NSLIP > 0
- #include <sys/types.h>
- #include <sys/stream.h>
- #include <sys/stropts.h>
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/user.h>
- #include <sys/errno.h>
- #include <sys/mbuf.h>
- #include <sys/socket.h>
- #include <sys/uio.h>
- #include <sys/ioctl.h>
- #include <sys/file.h>
- #include <net/if.h>
- #include <net/netisr.h>
- #include <netinet/in.h>
- #include <netinet/in_var.h>
- #include <sys/syslog.h>
-
- #include <sys/slip.h> /* needed for SLIPMTU (should be derived from
- underlying streams module for PPP), and SLIOGUNIT */
-
-
- static int rput();
- static int wput();
- static int if_in();
- static int stream_open();
- static int stream_close();
- static int stream_ioctl();
- static int if_out();
- static int if_ioc();
-
- static struct module_info minfo = { 518, "str_ip", 0, INFPSZ, 1024, 1024};
-
- static struct qinit rinit = {
- rput, if_in, stream_open, stream_close, NULL, &minfo, NULL
- };
- static struct qinit winit = {
- wput, NULL, NULL, NULL, NULL, &minfo, NULL
- };
-
- struct streamtab streams_ip = { &rinit, &winit, NULL, NULL };
-
- typedef struct {
- queue_t *q;
- struct ifnet i
- } ifhead ;
-
- static ifhead ifheads[NSLIP];
-
- static int stream_open(q,dev,flag,sflag)
- queue_t *q;
- dev_t dev;
- int flag;
- int sflag;
- {
- struct ifnet *ifp;
-
- if(!suser()) {
- u.u_error = EPERM;
- return(OPENFAIL);
- }
-
- for ( dev = 0 ; dev < NSLIP ; dev++)
- if ( !ifheads[dev].q )
- break;
-
- if (dev > NSLIP)
- return(OPENFAIL);
-
- ifp = &ifheads[dev].i;
- WR(q)->q_ptr = q->q_ptr = (caddr_t)&ifheads[dev];
- ifheads[dev].q = q;
-
- if (!ifp->if_mtu) {
- ifp->if_name = "slip";
- ifp->if_mtu = SLIPMTU;
- ifp->if_flags = IFF_POINTOPOINT;
- ifp->if_unit = dev;
- ifp->if_ioctl = if_ioc;
- ifp->if_output = if_out;
- ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
-
- if_attach(ifp);
- }
-
- return(ifp->if_unit);
- }
-
- static int stream_close(q,flag)
- queue_t *q;
- int flag;
- {
- ((ifhead *)(q->q_ptr))->q = NULL;
- ((ifhead *)(q->q_ptr))->i.if_flags &= ~IFF_UP;
- q->q_ptr = NULL;
- }
-
- static int wput(q,mp)
- queue_t *q;
- mblk_t *mp;
- {
- struct iocblk *iocp;
-
- switch (mp->b_datap->db_type) {
- case M_FLUSH:
- if (*mp->b_rptr & FLUSHW)
- flushq(q, FLUSHDATA);
- case M_IOCTL:
- iocp = (struct iocblk *) mp->b_rptr;
- switch(iocp->ioc_cmd) {
- case SLIOGUNIT:
- if ((mp->b_cont = allocb(sizeof(int),BPRI_MED)) == NULL) {
- mp->b_datap->db_type = M_IOCNAK;
- iocp->ioc_error = ENOSR;
- } else {
- mp->b_datap->db_type = M_IOCACK;
- *((int *)(mp->b_cont->b_wptr)) =
- ((ifhead *)(q->q_ptr))->i.if_unit;
- mp->b_cont->b_wptr += sizeof(int);
- iocp->ioc_count = sizeof(int);
- iocp->ioc_error = 0;
- }
- break;
- default:
- putnext(q,mp);
- return;
- }
- qreply(q,mp);
- break;
- default:
- putnext(q,mp);
- }
- }
-
- static int rput(q,mp)
- queue_t *q;
- mblk_t *mp;
- {
- switch (mp->b_datap->db_type) {
- case M_DATA:
- case M_FLUSH:
- putq(q,mp);
- break;
- default:
- putnext(q,mp);
- }
- }
-
- static int if_out(ifp, m0, dst)
- struct ifnet *ifp;
- struct mbuf *m0;
- struct sockaddr *dst;
- {
- int len = 0;
- queue_t *q = ifheads[ifp->if_unit].q;
- struct mbuf *m;
- mblk_t *mp;
- int s;
-
- if (q == 0) {
- m_freem(m0);
- return(EHOSTDOWN);
- }
-
- ifp->if_opackets++;
- switch (dst->sa_family) {
-
- case AF_INET:
- for (m = m0; m!= 0 ; m = m->m_next) {
- len += m->m_len;
- }
- if ((mp = allocb(len, BPRI_MED)) == NULL) {
- ifp->if_oerrors++;
- m_freem(m0);
- return(ENOSR);
- }
- for (m = m0; m!= 0 ; m = m->m_next) {
- bcopy(mtod(m, u_char *),mp->b_wptr,m->m_len);
- mp->b_wptr += m->m_len;
- }
- s = splstr();
- if (q)
- putnext(WR(q),mp);
- else
- freemsg(mp);
- splx(s);
- m_freem(m0);
- break;
- default:
- m_freem(m0);
- return(EAFNOSUPPORT);
- }
- return(0);
- }
-
- static int if_in(q)
- queue_t *q;
- {
- mblk_t *mp, *bp;
- int len;
- struct mbuf *m;
- struct ifnet *ifp = &((ifhead*)q->q_ptr)->i;
- int offset;
- int s;
-
-
- while ((mp = getq(q)) != NULL) {
- switch (mp->b_datap->db_type) {
- default: /* paranoid */
- putnext(q,mp);
- continue;
- case M_FLUSH:
- if (*mp->b_rptr & FLUSHR)
- flushq(q, FLUSHDATA);
- putnext(q,mp);
- continue;
- case M_DATA:
- MGET(m, M_DONTWAIT, MT_DATA); /* get an MBUF */
- if(!m) { /* dropit */
- ifp->if_ierrors++;
- freemsg(mp);
- log(LOG_ERR,"slip: MGET FAILED\n");
- continue;
- }
-
- len = sizeof(ifp);
- for (bp = mp; bp != 0 ; bp = bp->b_cont ) {
- len += bp->b_wptr - bp->b_rptr;
- }
-
- if (len > MLEN) {
- if (len > MCLBYTES) {
- ifp->if_ierrors++;
- freemsg(mp);
- m_freem(m);
- continue;
- }
- MCLGET(m);
- if (m->m_len == MLEN) {
- ifp->if_ierrors++;
- freemsg(mp);
- m_freem(m);
- log(LOG_ERR,"slip: MCLGET FAILED\n");
- continue;
- }
-
- }
- /* assert mbuf big enough to hold whole message */
-
- /* copy pointer */
- bcopy((char*)&ifp,mtod(m,char*),offset=sizeof(ifp));
-
- /* copy data */
- for (bp = mp; bp != 0 ; bp = bp->b_cont ) {
- bcopy(bp->b_rptr,mtod(m,char*)+offset,bp->b_wptr - bp->b_rptr);
- offset += bp->b_wptr - bp->b_rptr;
- bp->b_rptr = bp->b_wptr;
- }
- m->m_len = offset;
-
- ifp->if_ipackets++;
- /* enqueue / drop */
- s = splimp();
- if (IF_QFULL(&ipintrq)) {
- IF_DROP(&ipintrq);
- ifp->if_ierrors++;
- m_freem(m);
- (void) splx(s);
- log(LOG_ERR,"slip: IF_QFULL\n");
- } else {
- IF_ENQUEUE(&ipintrq, m);
- schednetisr(NETISR_IP);
- (void) splx(s);
- }
- freemsg(mp);
- }
- }
- }
-
- static int if_ioc(ifp, cmd, data)
- struct ifnet *ifp;
- int cmd;
- caddr_t data;
- {
- struct ifaddr *ifa = (struct ifaddr *)data;
- int s;
- int error = 0;
-
- if (ifa == NULL)
- return(EFAULT);
- s = splimp();
- switch (cmd) {
- case SIOCSIFADDR:
- switch (ifa->ifa_addr.sa_family) {
- case AF_INET:
- ifp->if_flags |= IFF_UP;
- break;
- default:
- error = EAFNOSUPPORT;
- break;
- }
- break;
- case SIOCSIFDSTADDR:
- switch (ifa->ifa_addr.sa_family) {
- case AF_INET:
- break;
- default:
- error = EAFNOSUPPORT;
- break;
- }
- break;
- default:
- error = EINVAL;
- }
- splx(s);
- return(error);
- }
- #endif
-