u-isdn/van_j/van_j.c

481 lines
9.5 KiB
C

/* Streams module to do Van Jacobsen TCP/IP compression */
#include "f_module.h"
#include "primitives.h"
#include "f_ip.h"
#include "f_malloc.h"
#include "ppp.h"
#include "kernel.h"
#include "f_signal.h"
#include "streams.h"
#include "stropts.h"
#ifdef DONT_ADDERROR
#include "f_user.h"
#endif
#include "vanj.h"
#include "van_j.h"
#include "compress.h"
#include "streamlib.h"
#include "isdn_proto.h"
static struct module_info van_j_minfo =
{
0, "van_j", 0, INFPSZ, 200,100
};
static qf_open van_j_open;
static qf_close van_j_close;
static qf_put van_j_rput,van_j_wput;
static qf_srv van_j_rsrv,van_j_wsrv;
static struct qinit van_j_rinit =
{
van_j_rput, van_j_rsrv, van_j_open, van_j_close, NULL, &van_j_minfo, NULL
};
static struct qinit van_j_winit =
{
van_j_wput, van_j_wsrv, NULL, NULL, NULL, &van_j_minfo, NULL
};
struct streamtab van_jinfo =
{&van_j_rinit, &van_j_winit, NULL, NULL};
#define NVAN_J 16
static struct _van_j {
queue_t *q_ptr;
struct compress comp;
char flags;
#define FLAGS_VANJ (VAN_J_ACTIVE|VAN_J_PASSIVE|VAN_J_PPP)
ushort_t offsetup, offsetdown;
} van_j_van_j[NVAN_J];
static void
van_j_proto (queue_t * q, mblk_t * mp, char isdown)
{
register struct _van_j *van_j = (struct _van_j *) q->q_ptr;
streamchar *origmp = mp->b_rptr;
ushort_t id;
/* In case we want to printf("%s") this... */
if (mp->b_wptr < DATA_END(mp))
*mp->b_wptr = '\0';
if (m_getid (mp, &id) != 0) {
mp->b_rptr = origmp;
putnext (q, mp);
return;
}
switch (id) {
default:
break;
case PROTO_OFFSET:
{
long z;
if (m_geti (mp, &z) != 0)
goto err;
if (z < 0 || z >= 1024)
goto err;
if(isdown) {
if (van_j->flags & VAN_J_PPP)
van_j->offsetup = z+2;
else
van_j->offsetup = 0;
} else {
if (van_j->flags & VAN_J_PPP)
van_j->offsetdown = z+2;
else
van_j->offsetdown = 0;
}
break;
}
case PROTO_CONNECTED:
van_j->flags |= VAN_J_CONN;
if ((van_j->flags & (VAN_J_ACTIVE | VAN_J_PASSIVE)) ==
(VAN_J_ACTIVE | VAN_J_PASSIVE))
van_j->flags &= ~VAN_J_ACTIVE;
break;
case PROTO_DISCONNECT:
printf ("X-Disconnect\n");
van_j->flags &= ~VAN_J_CONN;
break;
case PROTO_MODULE:
if (strnamecmp (q, mp)) {
u_long x;
if (van_j->flags & VAN_J_CONN)
goto err;
while (mp != NULL && m_getsx (mp, &id) == 0) {
switch (id) {
default:
err:
printf (" :Err %s\n", mp->b_rptr);
mp->b_rptr = origmp;
m_reply (q, mp, EINVAL);
mp = NULL;
case PROTO_MODULE:
break;
case VANJ_PPP:
if (van_j->flags & VAN_J_CONN)
break;
if(!(van_j->flags & VAN_J_PPP)) {
van_j->offsetup += 2;
van_j->offsetdown += 2;
}
van_j->flags |= VAN_J_PPP;
break;
case VANJ_NORM:
if (van_j->flags & VAN_J_CONN)
break;
if(van_j->flags & VAN_J_PPP) {
if (van_j->offsetup >= 2)
van_j->offsetup -= 2;
if (van_j->offsetdown >= 2)
van_j->offsetdown -= 2;
}
van_j->flags &= ~VAN_J_PPP;
break;
case VANJ_MODE:
if (van_j->flags & VAN_J_CONN)
break;
if (m_getx (mp, &x) != 0)
goto err;
switch (x) {
case VANJ_MODE_OFF:
van_j->flags &= ~VAN_J_ACTIVE;
van_j->flags &= ~VAN_J_PASSIVE;
break;
case VANJ_MODE_PASSIVE:
van_j->flags &= ~VAN_J_ACTIVE;
van_j->flags |= VAN_J_PASSIVE;
break;
case VANJ_MODE_ACTIVE:
van_j->flags |= VAN_J_ACTIVE;
van_j->flags &= ~VAN_J_PASSIVE;
break;
default:
goto err;
}
}
}
if (mp != NULL) {
mp->b_rptr = origmp;
m_reply (q,mp,0);
mp = NULL;
}
}
}
if (mp != NULL) {
if (origmp != NULL)
mp->b_rptr = origmp;
putnext (q, mp);
}
}
static int
van_j_open (queue_t * q, dev_t dev, int flag, int sflag ERR_DECL)
{
struct _van_j *van_j;
if(q->q_ptr != NULL)
return 0;
van_j = malloc(sizeof(van_j));
if(van_j == NULL)
ERR_RETURN(-ENOMEM);
memset(van_j,0,sizeof(*van_j));
WR (q)->q_ptr = (char *) van_j;
q->q_ptr = (char *) van_j;
van_j->flags = VAN_J_ACTIVE;
compress_init (&van_j->comp);
MORE_USE;
return 0;
}
static void
van_j_wput (queue_t * q, mblk_t * mp)
{
switch (DATA_TYPE(mp)) {
case MSG_PROTO:
case CASE_DATA:
putq (q, mp);
break;
case M_FLUSH:
if (*mp->b_rptr & FLUSHW)
flushq (q, FLUSHDATA);
putnext (q, mp);
break;
default:{
putnext (q, mp);
break;
}
}
return;
}
static void
van_j_wsrv (queue_t * q)
{
mblk_t *mp;
register struct _van_j *van_j = (struct _van_j *) q->q_ptr;
while ((mp = getq (q)) != NULL) {
switch (DATA_TYPE(mp)) {
case MSG_PROTO:
van_j_proto (q, mp, 1);
break;
case CASE_DATA:
{
mblk_t *mq;
struct ip *p_ip;
ushort_t protocol;
if(!canput(q->q_next)) {
putbq(q,mp);
return;
}
mq = pullupm (mp, 128); /* IP header, stuff */
if (mq == NULL) {
putbqf (q, mp);
return;
}
p_ip = (struct ip *)mq->b_rptr;
if (van_j->flags & VAN_J_PPP) {
protocol = *(u_short *)mq->b_rptr;
if ((p_ip->ip_p == PPP_IP) && (van_j->flags & VAN_J_ACTIVE)) {
mq->b_rptr += 2;
protocol = compress_tcp (&van_j->comp, &mq);
if(mq->b_rptr-2 < DATA_START(mq)) {
mp = allocb (van_j->offsetdown, BPRI_MED);
if (mp == NULL) {
freemsg (mq);
return;
}
DATA_TYPE(mp) = DATA_TYPE(mq);
mp->b_rptr += van_j->offsetdown;
mp->b_wptr += van_j->offsetdown;
linkb (mp, mq);
mq = mp;
}
mq->b_rptr -= 2;
*(ushort_t *)mq->b_rptr = protocol;
}
} else {
p_ip = (struct ip *) mq->b_rptr;
if (p_ip->ip_p == IPPROTO_TCP
&& van_j->flags & VAN_J_ACTIVE)
protocol = compress_tcp (&van_j->comp, &mq);
else
protocol = htons (PPP_PROTO_IP);
switch (ntohs (protocol)) {
case PPP_PROTO_VJC_COMP:
*mq->b_rptr |= 0x80;
break;
case PPP_PROTO_VJC_UNCOMP:
*mq->b_rptr |= 0x70;
break;
default:
break;
}
}
putnext (q, mq);
continue;
}
case M_FLUSH:
if (*mp->b_rptr & FLUSHW)
flushq (q, FLUSHDATA);
/* FALL THRU */
default:
if (DATA_TYPE(mp) > QPCTL || canput (q->q_next)) {
putnext (q, mp);
continue;
} else {
putbq (q, mp);
return;
}
}
}
return;
}
static void
van_j_close (queue_t * q, int dummy)
{
struct _van_j *van_j = (struct _van_j *) q->q_ptr;
flushq (q, FLUSHALL);
flushq (WR (q), FLUSHALL);
printf ("VAN_J driver %d closed.\n", van_j - van_j_van_j);
free(van_j);
LESS_USE;
return;
}
static void
van_j_rput (queue_t * q, mblk_t * mp)
{
switch (DATA_TYPE(mp)) {
case M_FLUSH:
if (*mp->b_rptr & FLUSHR) {
flushq (q, FLUSHDATA);
}
putnext (q, mp); /* send it along too */
break;
case MSG_PROTO:
case CASE_DATA:
putq (q, mp); /* queue it for my service routine */
break;
case M_HANGUP:
case M_ERROR:
default:
putnext (q, mp); /* don't know what to do with this, so send
* it along */
}
return;
}
static void
van_j_rsrv (queue_t * q)
{
mblk_t *mp;
register struct _van_j *van_j = (struct _van_j *) q->q_ptr;
while ((mp = getq (q)) != NULL) {
switch (DATA_TYPE(mp)) {
case MSG_PROTO:
van_j_proto (q, mp, 0);
break;
case CASE_DATA:
{
mblk_t *mq;
ushort_t protocol = 0;
if(!canput(q->q_next)) {
putbq(q,mp);
return;
}
if (van_j->flags & VAN_J_PPP) {
mq = pullupm (mp, 2);
if (mq == NULL) {
putbqf (q, mp);
return;
}
protocol = *(ushort_t *) mq->b_rptr;
mq->b_rptr += 2;
mp = pullupm (mq, 0);
} else {
uchar_t ch = *mp->b_rptr;
if (ch & 0x80) {
if (van_j->flags & VAN_J_ACTIVE)
protocol = PPP_PROTO_VJC_COMP;
else {
printf("VJ: packet dropped, not active\n");
freemsg (mp), mp = NULL;
}
} else if (ch >= 0x70) {
protocol = PPP_PROTO_VJC_UNCOMP;
*mp->b_rptr &= ~0x30;
van_j->flags |= VAN_J_ACTIVE;
} else
protocol = htons (PPP_PROTO_IP);
}
if (mp != NULL) {
switch (ntohs (protocol)) {
case PPP_PROTO_VJC_COMP:
mq = pullupm(mp,16);
if(mq == NULL) {
putbqf(q,mp);
return;
}
mp = mq;
uncompress_tcp (&van_j->comp, &mp, protocol);
protocol = PPP_IP;
break;
case PPP_PROTO_VJC_UNCOMP:
mq = pullupm(mp,128);
if(mq == NULL) {
putbqf(q,mp);
return;
}
mp = mq;
uncompress_tcp (&van_j->comp, &mp, protocol);
protocol = PPP_IP;
break;
case PPP_PROTO_IP:
break;
default:
printf ("VanJ: Unknown protocol 0x%x\n", ntohs (protocol));
freemsg (mp);
mp = NULL;
}
if (van_j->flags & VAN_J_PPP) {
if(mp->b_rptr-2 < DATA_START(mp)) {
mq = allocb (van_j->offsetup, BPRI_MED);
if (mq == NULL) {
freemsg (mp);
return;
}
DATA_TYPE(mq) = DATA_TYPE(mp);
mq->b_wptr += van_j->offsetup;
mq->b_rptr += van_j->offsetup;
linkb (mq, mp);
mp = mq;
}
mp->b_rptr -= 2;
*(ushort_t *)mp->b_rptr = protocol;
}
}
if (mp != NULL)
putnext (q, mp);
}
break;
default:
if (DATA_TYPE(mp) > QPCTL || canput (q->q_next)) {
putnext (q, mp);
continue;
} else {
putbq (q, mp);
return;
}
}
}
return;
}
#ifdef MODULE
static int do_init_module(void)
{
return register_strmod(&van_jinfo);
}
static int do_exit_module(void)
{
return unregister_strmod(&van_jinfo);
}
#endif