This is ppp_if.c in view mode; [Download] [Up]
/* ppp_if.c - Streams PPP top level module handles if_ and packetizing PPP packets.
Copyright (C) 1990 Brad K. Clements, All Rights Reserved
See copyright notice in Readme.streams
*/
#define VJC 1
#include <sys/types.h>
#include "ppp.h"
#if NPPP > 0
#define STREAMS 1
#define PPP_STATS 1
#define DEBUGS 1
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/user.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <net/if.h>
#include <net/netisr.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#ifdef PPP_STATS
#include <sys/slip_var.h>
#define INCR(comp) ++p->pii_stats.comp
#else
#define INCR(comp)
#endif
#ifdef VJC
#include "slcompress.h"
#endif
#include <sys/if_ppp.h>
#include <sys/ppp_str.h>
#ifdef DEBUGS
#include <sys/syslog.h>
#define DLOG(s,a) if(ppp_if_debug) log(LOG_INFO, s, a)
int ppp_if_debug=0;
#else
#define DLOG(s) {}
#endif
static int ppp_if_open(), ppp_if_close(), ppp_if_rput(), ppp_if_wput(),
ppp_if_wsrv(), ppp_if_rsrv();
static struct module_info minfo ={
0xbad,"ppp_if",0, INFPSZ, 16384, 4096
};
static struct qinit r_init = {
ppp_if_rput, ppp_if_rsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL
};
static struct qinit w_init = {
ppp_if_wput, ppp_if_wsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL
};
struct streamtab ppp_ifinfo = {
&r_init, &w_init, NULL, NULL, NULL
};
#ifdef OLD
struct ppp_if_info {
int pii_flags;
#define PII_FLAGS_INUSE 0x1 /* in use by a stream */
#define PII_FLAGS_COMPAC 0x2
#define PII_FLAGS_COMPPROT 0x4
#define PII_FLAGS_ATTACHED 0x8 /* already if_attached */
#define PII_FLAGS_VJC_ON 0x10 /* VJ TCP header compression enabled */
struct ifnet pii_ifnet;
queue_t *pii_writeq; /* used by ppp_output */
#ifdef VJC
struct slcompress pii_sc_comp; /* vjc control buffer */
#endif
};
#endif
typedef struct ppp_if_info PII;
PII pii[NPPP];
int ppp_output(), ppp_ioctl();
int
ppp_attach(unit)
int unit;
{
register struct ifnet *ifp = &pii[unit].pii_ifnet;
ifp->if_name = "ppp";
ifp->if_mtu = PPP_MTU;
ifp->if_flags = IFF_POINTOPOINT;
ifp->if_unit = unit;
ifp->if_ioctl = ppp_ioctl;
ifp->if_output = ppp_output;
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(ifp);
pii[unit].pii_flags |= PII_FLAGS_ATTACHED;
}
static int
ppp_if_open(q, dev, flag, sflag)
queue_t *q;
dev_t dev;
int flag,
sflag;
{
register PII *p;
register int x;
int s;
if(!suser()) {
u.u_error = EPERM;
return(OPENFAIL);
}
s = splstr();
if(!q->q_ptr) {
for(x=0; x < NPPP; x++) {
if(!(pii[x].pii_flags & PII_FLAGS_INUSE)) { /* we can use it */
p = &pii[x];
#ifdef VJC
#ifdef PPP_STATS
bzero(&p->pii_stats,sizeof(p->pii_stats));
#endif
#ifdef JUNK
if(!p->pii_sc_comp) {
p->pii_sc_comp = (struct slcompress *) kmem_alloc(sizeof(struct slcompress));
if(!p->pii_sc_comp) {
u.u_error = ENOSR;
return(OPENFAIL);
}
}
#endif
sl_compress_init(&p->pii_sc_comp);
#endif
if(!(p->pii_flags & PII_FLAGS_ATTACHED))
ppp_attach(x); /* attach it */
p->pii_writeq = WR(q);
WR(q)->q_ptr = q->q_ptr = (caddr_t) p; /* set write Q and read Q to point here */
p->pii_ifnet.if_flags |= IFF_RUNNING;
p->pii_flags = PII_FLAGS_INUSE|PII_FLAGS_ATTACHED;
DLOG("ppp_if%d: open\n",x);
splx(s);
return(x);
}
}
}
else {
p = (PII *) q->q_ptr;
#ifdef VJC
#ifdef PPP_STATS
bzero(&p->pii_stats,sizeof(p->pii_stats));
#endif
#ifdef JUNK
if(!p->pii_sc_comp) {
p->pii_sc_comp = (struct slcompress *) kmem_alloc(sizeof(struct slcompress));
if(!p->pii_sc_comp) {
u.u_error = ENOSR;
return(OPENFAIL);
}
}
#endif
sl_compress_init(&p->pii_sc_comp);
#endif
DLOG("ppp_if%d: reopen\n", (p-pii)/sizeof(PII));
if(!(p->pii_flags & PII_FLAGS_ATTACHED))
ppp_attach(x); /* attach it */
p->pii_writeq = WR(q);
WR(q)->q_ptr = q->q_ptr = (caddr_t) p; /* set write Q and read Q to point here */
p->pii_ifnet.if_flags |= IFF_RUNNING;
p->pii_flags = PII_FLAGS_INUSE|PII_FLAGS_ATTACHED;
splx(s);
return(0);
}
splx(s);
return(OPENFAIL);
}
static int
ppp_if_close(q)
queue_t *q; /* queue info */
{
PII *p = (PII *) q->q_ptr;
int s;
s = splimp();
p->pii_flags &= ~PII_FLAGS_INUSE;
if_down(&p->pii_ifnet);
p->pii_ifnet.if_flags &= ~IFF_RUNNING;
#ifdef VJC
#ifdef JUNK
if(p->pii_sc_comp)
kmem_free(p->pii_sc_comp);
#endif
#endif
DLOG("ppp_if%d: closed\n", (p-pii)/sizeof(PII));
splx(s);
return(0); /* no work to be done */
}
static int
ppp_if_wput(q, mp)
queue_t *q;
register mblk_t *mp;
{
register struct iocblk *i;
register PII *p;
switch (mp->b_datap->db_type) {
case M_FLUSH :
if(*mp->b_rptr & FLUSHW)
flushq(q, FLUSHDATA);
putnext(q, mp); /* send it along too */
break;
case M_DATA :
putq(q, mp); /* queue it for my service routine */
break;
case M_IOCTL :
i = (struct iocblk *) mp->b_rptr;
p = (PII *) q->q_ptr;
switch (i->ioc_cmd) {
case SIOCSIFCOMPAC : /* enable or disable AC compression */
if(i->ioc_count != sizeof(u_char))
goto passalong;
DLOG("ppp_if: SIFCOMPAC %d\n", *(u_char *) mp->b_cont->b_rptr);
if( *(u_char *) mp->b_cont->b_rptr)
p->pii_flags |= PII_FLAGS_COMPAC;
else
p->pii_flags &= ~PII_FLAGS_COMPAC;
goto passalong;
case SIOCSIFCOMPPROT: /* enable or disable PROT compression */
DLOG("ppp_if: SIFCOMPPROT %d\n", *(u_char *) mp->b_cont->b_rptr);
if(i->ioc_count != sizeof(u_char))
goto passalong;
if( *(u_char *) mp->b_cont->b_rptr)
p->pii_flags |= PII_FLAGS_COMPPROT;
else
p->pii_flags &= ~PII_FLAGS_COMPPROT;
goto passalong;
case SIOCSIFVJCOMP: /* enable or disable VJ compression */
#ifdef VJC
if(i->ioc_count != sizeof(u_char))
goto passalong;
DLOG("ppp_if: SIFVJCOMP %d\n", *(u_char *) mp->b_cont->b_rptr);
if( *(u_char *) mp->b_cont->b_rptr)
p->pii_flags |= PII_FLAGS_VJC_ON;
else
p->pii_flags &= ~PII_FLAGS_VJC_ON;
mp->b_datap->db_type = M_IOCACK;
#else
mp->b_datap->db_type = M_IOCNAK;
i->ioc_error = EINVAL;
i->ioc_count = 0;
#endif
qreply(q,mp);
break;
case SIOCGETU : /* get unit number */
if(mp->b_cont = allocb(sizeof(int), BPRI_MED)) {
*(int *) mp->b_cont->b_wptr = p->pii_ifnet.if_unit;
mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
mp->b_datap->db_type = M_IOCACK;
qreply(q,mp);
break;
}
i->ioc_error = ENOSR;
i->ioc_count = 0;
mp->b_datap->db_type = M_IOCNAK;
qreply(q, mp);
break;
default: /* unknown IOCTL call */
passalong:;
putnext(q,mp); /* pass it along */
}
DLOG("ppp: Pii->flags 0x%x\n",p->pii_flags);
break;
default :
putnext(q,mp); /* don't know what to do with this, so send it along*/
}
}
static int
ppp_if_wsrv(q)
queue_t *q;
{
register mblk_t *mp;
register PII *p;
p = (PII *) q->q_ptr;
while((mp = getq(q)) != NULL) {
/* we can only get M_DATA types into our Queue, due to our Put function */
if(!canput(q->q_next)) {
putbq(q, mp);
return;
}
p->pii_ifnet.if_opackets++; /* increment count of outgoing packets */
INCR(sl_opackets);
putnext(q, mp); /* just pass it along, nothing to do in this direction */
} /* end while */
}
static int
ppp_if_rput(q, mp)
queue_t *q;
register mblk_t *mp;
{
register u_char *c;
register PII *p;
switch (mp->b_datap->db_type) {
case M_FLUSH :
if(*mp->b_rptr & FLUSHR)
flushq(q, FLUSHDATA);
putnext(q, mp); /* send it along too */
break;
case M_DATA :
putq(q, mp); /* queue it for my service routine */
break;
case M_CTL : /* could be a message from below */
p = (PII *) q->q_ptr;
c = (u_char *) mp->b_rptr;
switch (c) {
case IF_INPUT_ERROR :
p->pii_ifnet.if_ierrors++;
INCR(sl_ierrors);
DLOG("ppp_if: input error inc to %d\n", p->pii_ifnet.if_ierrors);
break;
case IF_OUTPUT_ERROR :
p->pii_ifnet.if_oerrors++;
INCR(sl_oerrors);
DLOG("ppp_if: output error inc to %d\n", p->pii_ifnet.if_oerrors);
break;
default:;
break;
}
freemsg(mp);
/* putnext(q, mp); */
break;
default :
putnext(q,mp); /* don't know what to do with this, so send it along*/
}
}
static int
ppp_if_rsrv(q)
queue_t *q;
{
register mblk_t *mp,*m0;
#ifdef VJC
register mblk_t *mvjc;
unsigned char *cp;
#endif
register PII *p;
struct ifnet **ifp;
struct ppp_header *ph;
struct mbuf *mb1, *mb2,*mbtail;
int len,xlen,count,s;
u_char *rptr;
p = (PII *) q->q_ptr;
while((mp = getq(q)) != NULL) {
/* we can only get M_DATA types into our Queue, due to our Put function */
m0 = mp; /* remember first message block */
ph = (struct ppp_header *) mp->b_rptr;
/* assume ppp_header is completely in first block */
if(mp->b_wptr - mp->b_rptr < sizeof(struct ppp_header)) {
freemsg(mp);
p->pii_ifnet.if_ierrors++;
continue;
}
#ifdef VJC
switch (ntohs(ph->ph_protocol)) {
case PPP_IP :
break;
case PPP_VJC_COMP :
if(p->pii_flags & PII_FLAGS_VJC_ON) {
for(xlen=0, mvjc = mp; mvjc; mvjc = mvjc->b_cont)
xlen += (mvjc->b_wptr - mvjc->b_rptr);
xlen -= sizeof(struct ppp_header);
if(!(mvjc = allocb(128, BPRI_MED))) { /* get a 128 byte buffer for IP header*/
putbq(q,mp);
qenable(q);
return;
}
mvjc->b_wptr += 128;
linkb(mvjc,mp);
if(!pullupmsg(mvjc,-1)) { /* string em all together. ugh what a waste */
freemsg(mvjc);
continue;
}
cp = mvjc->b_rptr + 128 + sizeof(struct ppp_header);
m0 = mp = mvjc;
xlen = sl_uncompress_tcp(&cp,xlen, TYPE_COMPRESSED_TCP, &p->pii_sc_comp);
if(!xlen) {
DLOG("ppp: sl_uncompress failed on type Compressed",0);;
goto reject;
}
mp->b_rptr = cp - sizeof(struct ppp_header);
((struct ppp_header *) mp->b_rptr)->ph_protocol = htons(PPP_IP);
break;
}
case PPP_VJC_UNCOMP :
if(p->pii_flags & PII_FLAGS_VJC_ON) {
cp = (unsigned char *) mp->b_rptr + sizeof(struct ppp_header);
if(sl_uncompress_tcp(&cp, 1, TYPE_UNCOMPRESSED_TCP, &p->pii_sc_comp)) {
((struct ppp_header *) mp->b_rptr)->ph_protocol = htons(PPP_IP);
break;
}
DLOG("ppp: sl_uncompress failed on type Uncompresed\n",0);
reject:;
freemsg(mp);
continue;
}
default :;
#endif
#ifndef VJC
if(ntohs(ph->ph_protocol) != PPP_IP) {
#endif
DLOG("ppp: unknown protocol 0x%x\n",ntohs(ph->ph_protocol));
INCR(sl_ipackets);
if(!canput(q->q_next)) {
putbq(q, mp);
return;
}
putnext(q,mp);
p->pii_ifnet.if_ipackets++;
continue;
#ifndef VJC
}
#endif
}
len = 0;
mb1 = NULL;
xlen = mp->b_wptr - (rptr = mp->b_rptr);
while(mp) {
if(len < 1) {
MGET(mb2, M_DONTWAIT, MT_DATA);
if(!mb2) {
p->pii_ifnet.if_ierrors++;
putbq(q,m0);
qenable(q);
if(mb1)
m_freem(mb1); /* discard what we've used already */
return;
} /* if we couldn't get a buffer, put back the message and try later */
len = MLEN;
mb2->m_len = 0;
if(mb1) {
mbtail->m_next = mb2;
mbtail = mb2;
}
else
mbtail = mb1 = mb2;
}
count = MIN(xlen, len);
bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count);
#ifdef PPP_STATS
p->pii_stats.sl_ibytes += count;
#endif
rptr += count;
len -= count;
xlen -= count;
mb2->m_len += count;
if(!xlen) { /* move to the next mblk */
mp = mp->b_cont;
if(mp)
xlen = mp->b_wptr - (rptr = mp->b_rptr);
}
}
#define HADJ (sizeof(struct ppp_header) - sizeof(struct ifnet *))
/* note, HADJ >= 0 is assumed */
ifp = (struct ifnet **) (mtod(mb1, u_char *) + HADJ);
*ifp = &p->pii_ifnet; /* stick ifnet * in front of packet */
mb1->m_off += HADJ;
mb1->m_len -= HADJ;
freemsg(m0);
p->pii_ifnet.if_ipackets++;
INCR(sl_ipackets);
s = splimp();
if (IF_QFULL(&ipintrq)) {
IF_DROP(&ipintrq);
p->pii_ifnet.if_ierrors++;
m_freem(mb1);
}
else {
IF_ENQUEUE(&ipintrq, mb1);
schednetisr(NETISR_IP);
}
splx(s);
} /* end while */
}
/* ifp output procedure */
int
ppp_output(ifp, m0, dst)
struct ifnet *ifp;
struct mbuf *m0;
struct sockaddr *dst;
{
register PII *p = &pii[ifp->if_unit];
struct mbuf *m1;
int error,s, len;
u_short protocol;
#ifdef VJC
u_char type;
#endif
mblk_t *mp;
error = 0;
if((ifp->if_flags & IFF_RUNNING) != IFF_RUNNING || !p->pii_writeq) {
error = ENETDOWN;
goto getout;
}
switch (dst->sa_family) {
#ifdef INET
case AF_INET :
protocol = PPP_IP;
break;
#endif
#ifdef NS
case AF_NS :
protocol = PPP_XNS;
break;
#endif
default :;
printf("ppp%d: af%d not supported\n",ifp->if_unit, dst->sa_family);
error = EAFNOSUPPORT;
goto getout;
}
#ifdef VJC
if((protocol == PPP_IP) && (p->pii_flags & PII_FLAGS_VJC_ON)) {
register struct ip *ip;
ip = mtod(m0, struct ip *);
if(ip->ip_p == IPPROTO_TCP) {
type = sl_compress_tcp(m0, ip, &p->pii_sc_comp, 1);
switch (type) {
case TYPE_UNCOMPRESSED_TCP :
protocol = PPP_VJC_UNCOMP;
break;
case TYPE_COMPRESSED_TCP :
protocol = PPP_VJC_COMP;
break;
default :;
}
}
}
#endif
len = 0;
for(m1 = m0; m1; m1 = m1->m_next)
len += m1->m_len;
if(!(p->pii_flags & PII_FLAGS_COMPAC))
len += 2; /* if we are not compac, then need 2 extra bytes */
if(p->pii_flags & PII_FLAGS_COMPPROT)
len += 1;
else
len += 2; /* we never need to check the actual protocol, since its always
either PPP_IP,PPP_VJC_* or PPP_XNS
*/
if(!(mp = allocb(len, BPRI_LO))) {
error = ENOBUFS;
goto getout;
}
#ifdef PPP_STATS
p->pii_stats.sl_obytes += len;
#endif
if(!(p->pii_flags & PII_FLAGS_COMPAC)) {
*mp->b_wptr++ = PPP_ALLSTATIONS;
*mp->b_wptr++ = PPP_UI;
}
if(!(p->pii_flags & PII_FLAGS_COMPPROT))
*mp->b_wptr++ = 0;
*mp->b_wptr++ = protocol & 0xff;
for(m1 = m0; m1; m1 = m1->m_next) { /* copy all data */
bcopy(mtod(m1, char *), (char *) mp->b_wptr, m1->m_len);
mp->b_wptr += m1->m_len;
}
s = splstr();
putq(p->pii_writeq, mp);
splx(s);
p->pii_ifnet.if_opackets++;
INCR(sl_opackets);
getout:;
m_freem(m0);
if(error) {
INCR(sl_oerrors);
p->pii_ifnet.if_oerrors++;
}
return(error); /* gads, streams are great */
}
/*
* if_ ioctl requests
*/
ppp_ioctl(ifp, cmd, data)
register struct ifnet *ifp;
int cmd;
caddr_t data;
{
register struct ifaddr *ifa = (struct ifaddr *) data;
register struct ifreq *ifr = (struct ifreq *) data;
int s = splimp(), error = 0;
if(ifa == NULL ) {
splx(s);
return(EFAULT);
}
switch (cmd) {
case SIOCSIFFLAGS :
if(!suser()) {
error = EPERM;
break;
}
ifp->if_flags &= (IFF_CANTCHANGE); /* clear the flags that can be cleared */
ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE); /* or in the flags that can
be changed */
break;
case SIOCGIFFLAGS :
ifr->ifr_flags = ifp->if_flags;
break;
case SIOCSIFADDR :
if( ifa->ifa_addr.sa_family != AF_INET)
error = EAFNOSUPPORT;
break;
case SIOCSIFDSTADDR :
if(ifa->ifa_addr.sa_family != AF_INET)
error = EAFNOSUPPORT;
break;
case SIOCSIFMTU :
if(!suser()) {
error = EPERM;
break;
}
if(ifr->ifr_mtu > (4096 - (sizeof(struct ppp_header) + sizeof(u_short)))) {
error = EINVAL;
break;
}
ifp->if_mtu = ifr->ifr_mtu;
break;
case SIOCGIFMTU :
ifr->ifr_mtu = ifp->if_mtu;
break;
default :;
error = EINVAL;
break;
}
splx(s);
return(error);
}
#endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.