vjcomp.c revision 54913
16059Samurai/*
26059Samurai *	       Input/Output VJ Compressed packets
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
2050479Speter * $FreeBSD: head/usr.sbin/ppp/vjcomp.c 54913 1999-12-20 20:29:51Z brian $
218857Srgrimes *
226059Samurai *  TODO:
236059Samurai */
2443313Sbrian#include <sys/param.h>
2530715Sbrian#include <netinet/in.h>
2630715Sbrian#include <netinet/in_systm.h>
2730715Sbrian#include <netinet/ip.h>
2836285Sbrian#include <sys/un.h>
2930715Sbrian
3031061Sbrian#include <stdio.h>
3149472Sbrian#include <string.h>		/* strlen/memcpy */
3246686Sbrian#include <termios.h>
3330715Sbrian
3446686Sbrian#include "layer.h"
3530715Sbrian#include "mbuf.h"
3630715Sbrian#include "log.h"
3730715Sbrian#include "timer.h"
386059Samurai#include "fsm.h"
3946686Sbrian#include "proto.h"
406059Samurai#include "slcompress.h"
4136285Sbrian#include "lqr.h"
426059Samurai#include "hdlc.h"
4336285Sbrian#include "defs.h"
4436285Sbrian#include "iplist.h"
4536285Sbrian#include "throughput.h"
466059Samurai#include "ipcp.h"
4736285Sbrian#include "lcp.h"
4836285Sbrian#include "ccp.h"
4936285Sbrian#include "link.h"
5036285Sbrian#include "filter.h"
5136285Sbrian#include "descriptor.h"
5236285Sbrian#include "mp.h"
5343313Sbrian#ifndef NORADIUS
5443313Sbrian#include "radius.h"
5543313Sbrian#endif
5636285Sbrian#include "bundle.h"
5730715Sbrian#include "vjcomp.h"
586059Samurai
5928679Sbrian#define MAX_VJHEADER 16		/* Maximum size of compressed header */
606059Samurai
6146686Sbrianstatic struct mbuf *
6246686Sbrianvj_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, int pri,
6346686Sbrian             u_short *proto)
646059Samurai{
656059Samurai  int type;
6645103Sbrian  struct ip *pip;
6736285Sbrian  u_short cproto = bundle->ncp.ipcp.peer_compproto >> 16;
686059Samurai
6954912Sbrian  bp = m_pullup(bp);
7045103Sbrian  pip = (struct ip *)MBUF_CTOP(bp);
7146686Sbrian  if (*proto == PROTO_IP && pip->ip_p == IPPROTO_TCP &&
7246686Sbrian      cproto == PROTO_VJCOMP) {
7345103Sbrian    type = sl_compress_tcp(bp, pip, &bundle->ncp.ipcp.vj.cslc,
7436285Sbrian                           &bundle->ncp.ipcp.vj.slstat,
7536285Sbrian                           bundle->ncp.ipcp.peer_compproto & 0xff);
7646686Sbrian    log_Printf(LogDEBUG, "vj_LayerWrite: type = %x\n", type);
776059Samurai    switch (type) {
786059Samurai    case TYPE_IP:
796059Samurai      break;
8046686Sbrian
816059Samurai    case TYPE_UNCOMPRESSED_TCP:
8246686Sbrian      *proto = PROTO_VJUNCOMP;
8347061Sbrian      log_Printf(LogDEBUG, "vj_LayerPush: PROTO_IP -> PROTO_VJUNCOMP\n");
8454912Sbrian      m_settype(bp, MB_VJOUT);
856059Samurai      break;
8646686Sbrian
876059Samurai    case TYPE_COMPRESSED_TCP:
8846686Sbrian      *proto = PROTO_VJCOMP;
8947061Sbrian      log_Printf(LogDEBUG, "vj_LayerPush: PROTO_IP -> PROTO_VJUNCOMP\n");
9054912Sbrian      m_settype(bp, MB_VJOUT);
916059Samurai      break;
9246686Sbrian
936059Samurai    default:
9447061Sbrian      log_Printf(LogERROR, "vj_LayerPush: Unknown frame type %x\n", type);
9554912Sbrian      m_freem(bp);
9646686Sbrian      return NULL;
976059Samurai    }
9846686Sbrian  }
9936285Sbrian
10046686Sbrian  return bp;
1016059Samurai}
1026059Samurai
1036059Samuraistatic struct mbuf *
10446828SbrianVjUncompressTcp(struct ipcp *ipcp, struct mbuf *bp, u_char type)
1056059Samurai{
1066059Samurai  u_char *bufp;
1076059Samurai  int len, olen, rlen;
10828679Sbrian  u_char work[MAX_HDR + MAX_VJHEADER];	/* enough to hold TCP/IP header */
1096059Samurai
11054912Sbrian  bp = m_pullup(bp);
11154912Sbrian  olen = len = m_length(bp);
1126059Samurai  if (type == TYPE_UNCOMPRESSED_TCP) {
1136059Samurai    /*
11428679Sbrian     * Uncompressed packet does NOT change its size, so that we can use mbuf
11528679Sbrian     * space for uncompression job.
1166059Samurai     */
1176059Samurai    bufp = MBUF_CTOP(bp);
11836960Sbrian    len = sl_uncompress_tcp(&bufp, len, type, &ipcp->vj.cslc, &ipcp->vj.slstat,
11936960Sbrian                            (ipcp->my_compproto >> 8) & 255);
1206735Samurai    if (len <= 0) {
12154912Sbrian      m_freem(bp);
12232663Sbrian      bp = NULL;
12347695Sbrian    } else
12454912Sbrian      m_settype(bp, MB_VJIN);
12546686Sbrian    return bp;
1266059Samurai  }
12728679Sbrian
1286059Samurai  /*
12928679Sbrian   * Handle compressed packet. 1) Read upto MAX_VJHEADER bytes into work
13028679Sbrian   * space. 2) Try to uncompress it. 3) Compute amount of necesary space. 4)
13128679Sbrian   * Copy unread data info there.
1326059Samurai   */
13328679Sbrian  if (len > MAX_VJHEADER)
13428679Sbrian    len = MAX_VJHEADER;
1356059Samurai  rlen = len;
1366059Samurai  bufp = work + MAX_HDR;
13736285Sbrian  bp = mbuf_Read(bp, bufp, rlen);
13836960Sbrian  len = sl_uncompress_tcp(&bufp, olen, type, &ipcp->vj.cslc, &ipcp->vj.slstat,
13936960Sbrian                          (ipcp->my_compproto >> 8) & 255);
1406735Samurai  if (len <= 0) {
14154912Sbrian    m_freem(bp);
14232663Sbrian    return NULL;
1436735Samurai  }
1446059Samurai  len -= olen;
1456059Samurai  len += rlen;
14654913Sbrian
14754913Sbrian  bp = m_prepend(bp, bufp, len, 0);
14854912Sbrian  m_settype(bp, MB_VJIN);
14954913Sbrian
15054913Sbrian  return bp;
1516059Samurai}
1526059Samurai
15346686Sbrianstatic struct mbuf *
15446686Sbrianvj_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp,
15546686Sbrian             u_short *proto)
1566059Samurai{
1576059Samurai  u_char type;
1586059Samurai
15946686Sbrian  switch (*proto) {
1606059Samurai  case PROTO_VJCOMP:
1616059Samurai    type = TYPE_COMPRESSED_TCP;
16247061Sbrian    log_Printf(LogDEBUG, "vj_LayerPull: PROTO_VJCOMP -> PROTO_IP\n");
1636059Samurai    break;
1646059Samurai  case PROTO_VJUNCOMP:
1656059Samurai    type = TYPE_UNCOMPRESSED_TCP;
16647061Sbrian    log_Printf(LogDEBUG, "vj_LayerPull: PROTO_VJUNCOMP -> PROTO_IP\n");
1676059Samurai    break;
1686059Samurai  default:
16946686Sbrian    return bp;
1706059Samurai  }
17146686Sbrian
17246686Sbrian  *proto = PROTO_IP;
17346686Sbrian  return VjUncompressTcp(&bundle->ncp.ipcp, bp, type);
1746059Samurai}
17531514Sbrian
17631514Sbrianconst char *
17732439Sbrianvj2asc(u_int32_t val)
17831514Sbrian{
17937010Sbrian  static char asc[50];		/* The return value is used immediately */
18031514Sbrian
18136285Sbrian  if (val)
18246686Sbrian    snprintf(asc, sizeof asc, "%d VJ slots with%s slot compression",
18346686Sbrian            (int)((val>>8)&15)+1, val & 1 ?  "" : "out");
18436285Sbrian  else
18536285Sbrian    strcpy(asc, "VJ disabled");
18631514Sbrian  return asc;
18731514Sbrian}
18846686Sbrian
18946686Sbrianstruct layer vjlayer = { LAYER_VJ, "vj", vj_LayerPush, vj_LayerPull };
190