summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>2001-12-27 16:49:31 +0000
committerjoerg <joerg@FreeBSD.org>2001-12-27 16:49:31 +0000
commit5a94a8f0c9bc2c0d694461b6c7dc6bf970529d9d (patch)
tree128cc1b68b29a4b0017a65e3cfe5b6c8a9dca17d /sys/net
parent5a63bf2b8472db6e8ec874be6b65b167f2ee7ceb (diff)
downloadFreeBSD-src-5a94a8f0c9bc2c0d694461b6c7dc6bf970529d9d.zip
FreeBSD-src-5a94a8f0c9bc2c0d694461b6c7dc6bf970529d9d.tar.gz
Implement VJ header compression for sppp.
This is the logical merge of rev 1.32 of i4b's old if_spppsubr.c (which was based on PR misc/11767), plus (i4b) rev 1.6 of i4b's if_ispppsubr.c, albeit with numerous stylistic and cosmetic changes. PR: misc/11767 Submitted by: i4b, Joachim Kuebart MFC after: 1 month
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_sppp.h5
-rw-r--r--sys/net/if_spppsubr.c158
2 files changed, 158 insertions, 5 deletions
diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h
index 7560f59..c2d3e7d 100644
--- a/sys/net/if_sppp.h
+++ b/sys/net/if_sppp.h
@@ -51,6 +51,9 @@ struct sipcp {
#define IPV6CP_MYIFID_DYN 8 /* my ifid is dynamically assigned */
#endif
#define IPV6CP_MYIFID_SEEN 0x10 /* have seen his ifid already */
+#define IPCP_VJ 0x20 /* can use VJ compression */
+ int max_state; /* VJ: Max-Slot-Id */
+ int compress_cid; /* VJ: Comp-Slot-Id */
};
#define AUTHNAMELEN 32
@@ -99,6 +102,7 @@ struct sppp {
u_char confid[IDX_COUNT]; /* id of last configuration request */
int rst_counter[IDX_COUNT]; /* restart counter */
int fail_counter[IDX_COUNT]; /* negotiation failure counter */
+ int enable_vj; /* VJ header compression enabled */
struct callout_handle ch[IDX_COUNT]; /* per-proto and if callouts */
struct callout_handle pap_my_to_ch; /* PAP needs one more... */
struct slcp lcp; /* LCP params */
@@ -106,6 +110,7 @@ struct sppp {
struct sipcp ipv6cp; /* IPv6CP params */
struct sauth myauth; /* auth params, i'm peer */
struct sauth hisauth; /* auth params, i'm authenticator */
+ struct slcompress pp_comp; /* for VJ compression */
/*
* These functions are filled in by sppp_attach(), and are
* expected to be used by the lower layer (hardware) drivers
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index 2d3d97f..44db500 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -6,7 +6,7 @@
* Author: Serge Vakulenko, <vak@cronyx.ru>
*
* Heavily revamped to conform to RFC 1661.
- * Copyright (C) 1997, Joerg Wunsch.
+ * Copyright (C) 1997, 2001 Joerg Wunsch.
*
* This software is distributed with NO WARRANTIES, not even the implied
* warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -58,6 +58,10 @@
#include <net/netisr.h>
#include <net/if_types.h>
#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/slcompress.h>
#if defined (__NetBSD__) || defined (__OpenBSD__)
#include <machine/cpu.h> /* XXX for softnet */
@@ -135,6 +139,8 @@
#define PPP_ISO 0x0023 /* ISO OSI Protocol */
#define PPP_XNS 0x0025 /* Xerox NS Protocol */
#define PPP_IPX 0x002b /* Novell IPX Protocol */
+#define PPP_VJ_COMP 0x002d /* VJ compressed TCP/IP */
+#define PPP_VJ_UCOMP 0x002f /* VJ uncompressed TCP/IP */
#define PPP_IPV6 0x0057 /* Internet Protocol Version 6 */
#define PPP_LCP 0xc021 /* Link Control Protocol */
#define PPP_PAP 0xc023 /* Password Authentication Protocol */
@@ -170,6 +176,8 @@
#define IPV6CP_OPT_IFID 1 /* interface identifier */
#define IPV6CP_OPT_COMPRESSION 2 /* IPv6 compression protocol */
+#define IPCP_COMP_VJ 0x2d /* Code for VJ compression */
+
#define PAP_REQ 1 /* PAP name/password request */
#define PAP_ACK 2 /* PAP acknowledge */
#define PAP_NAK 3 /* PAP fail */
@@ -500,6 +508,7 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
struct ppp_header *h;
struct ifqueue *inq = 0;
struct sppp *sp = (struct sppp *)ifp;
+ int len;
int debug = ifp->if_flags & IFF_DEBUG;
if (ifp->if_flags & IFF_UP)
@@ -590,6 +599,32 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
inq = &ip6intrq;
}
break;
+ case PPP_VJ_COMP:
+ if (sp->state[IDX_IPCP] == STATE_OPENED) {
+ if ((len =
+ sl_uncompress_tcp((u_char **)&m->m_data,
+ m->m_len,
+ TYPE_COMPRESSED_TCP,
+ &sp->pp_comp)) <= 0)
+ goto drop;
+ m->m_len = m->m_pkthdr.len = len;
+ schednetisr (NETISR_IP);
+ inq = &ipintrq;
+ }
+ break;
+ case PPP_VJ_UCOMP:
+ if (sp->state[IDX_IPCP] == STATE_OPENED) {
+ if ((len =
+ sl_uncompress_tcp((u_char **)&m->m_data,
+ m->m_len,
+ TYPE_UNCOMPRESSED_TCP,
+ &sp->pp_comp)) <= 0)
+ goto drop;
+ m->m_len = m->m_pkthdr.len = len;
+ schednetisr (NETISR_IP);
+ inq = &ipintrq;
+ }
+ break;
#endif
#ifdef IPX
case PPP_IPX:
@@ -691,6 +726,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
struct ppp_header *h;
struct ifqueue *ifq = NULL;
int s, rv = 0;
+ int ipproto = PPP_IP;
int debug = ifp->if_flags & IFF_DEBUG;
s = splimp();
@@ -757,6 +793,28 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
ifq = &sp->pp_fastq;
else if (INTERACTIVE (ntohs (tcp->th_dport)))
ifq = &sp->pp_fastq;
+
+ /*
+ * Do IP Header compression
+ */
+ if (sp->pp_mode != IFF_CISCO && (sp->ipcp.flags & IPCP_VJ) &&
+ ip->ip_p == IPPROTO_TCP)
+ switch (sl_compress_tcp(m, ip, &sp->pp_comp,
+ sp->ipcp.compress_cid)) {
+ case TYPE_COMPRESSED_TCP:
+ ipproto = PPP_VJ_COMP;
+ break;
+ case TYPE_UNCOMPRESSED_TCP:
+ ipproto = PPP_VJ_UCOMP;
+ break;
+ case TYPE_IP:
+ ipproto = PPP_IP;
+ break;
+ default:
+ m_freem(m);
+ splx(s);
+ return (EINVAL);
+ }
}
#endif
@@ -806,7 +864,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
* not ready to carry IP packets, and return
* ENETDOWN, as opposed to ENOBUFS.
*/
- h->protocol = htons(PPP_IP);
+ h->protocol = htons(ipproto);
if (sp->state[IDX_IPCP] != STATE_OPENED)
rv = ENETDOWN;
}
@@ -896,7 +954,8 @@ sppp_attach(struct ifnet *ifp)
sp->pp_down = lcp.Down;
mtx_init(&sp->pp_cpq.ifq_mtx, "sppp_cpq", MTX_DEF);
mtx_init(&sp->pp_fastq.ifq_mtx, "sppp_fastq", MTX_DEF);
-
+ sp->enable_vj = 1;
+ sl_compress_init(&sp->pp_comp, -1);
sppp_lcp_init(sp);
sppp_ipcp_init(sp);
sppp_ipv6cp_init(sp);
@@ -2689,7 +2748,8 @@ sppp_ipcp_open(struct sppp *sp)
STDDCL;
u_long myaddr, hisaddr;
- sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN);
+ sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN | IPCP_MYADDR_SEEN |
+ IPCP_MYADDR_DYN | IPCP_VJ);
sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
/*
@@ -2705,7 +2765,6 @@ sppp_ipcp_open(struct sppp *sp)
SPP_ARGS(ifp));
return;
}
-
if (myaddr == 0L) {
/*
* I don't have an assigned address, so i need to
@@ -2715,6 +2774,11 @@ sppp_ipcp_open(struct sppp *sp)
sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
} else
sp->ipcp.flags |= IPCP_MYADDR_SEEN;
+ if (sp->enable_vj) {
+ sp->ipcp.opts |= (1 << IPCP_OPT_COMPRESSION);
+ sp->ipcp.max_state = MAX_STATES - 1;
+ sp->ipcp.compress_cid = 1;
+ }
sppp_open_event(&ipcp, sp);
}
@@ -2749,6 +2813,7 @@ sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
u_long hisaddr, desiredaddr;
int gotmyaddr = 0;
+ int desiredcomp;
len -= 4;
origlen = len;
@@ -2769,6 +2834,37 @@ sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
if (debug)
log(-1, " %s ", sppp_ipcp_opt_name(*p));
switch (*p) {
+ case IPCP_OPT_COMPRESSION:
+ if (!sp->enable_vj) {
+ /* VJ compression administratively disabled */
+ if (debug)
+ log(-1, "[locally disabled] ");
+ break;
+ }
+ /*
+ * In theory, we should only conf-rej an
+ * option that is shorter than RFC 1618
+ * requires (i.e. < 4), and should conf-nak
+ * anything else that is not VJ. However,
+ * since our algorithm always uses the
+ * original option to NAK it with new values,
+ * things would become more complicated. In
+ * pratice, the only commonly implemented IP
+ * compression option is VJ anyway, so the
+ * difference is negligible.
+ */
+ if (len >= 6 && p[1] == 6) {
+ /*
+ * correctly formed compression option
+ * that could be VJ compression
+ */
+ continue;
+ }
+ if (debug)
+ log(-1,
+ "optlen %d [invalid/unsupported] ",
+ p[1]);
+ break;
case IPCP_OPT_ADDRESS:
if (len >= 6 && p[1] == 6) {
/* correctly formed address option */
@@ -2807,6 +2903,27 @@ sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
if (debug)
log(-1, " %s ", sppp_ipcp_opt_name(*p));
switch (*p) {
+ case IPCP_OPT_COMPRESSION:
+ desiredcomp = p[2] << 8 | p[3];
+ /* We only support VJ */
+ if (desiredcomp == IPCP_COMP_VJ) {
+ if (debug)
+ log(-1, "VJ [ack] ");
+ sp->ipcp.flags |= IPCP_VJ;
+ sl_compress_init(&sp->pp_comp, p[4]);
+ sp->ipcp.max_state = p[4];
+ sp->ipcp.compress_cid = p[5];
+ continue;
+ }
+ if (debug)
+ log(-1,
+ "compproto %#04x [not supported] ",
+ desiredcomp);
+ p[2] = IPCP_COMP_VJ >> 8;
+ p[3] = IPCP_COMP_VJ;
+ p[4] = sp->ipcp.max_state;
+ p[5] = sp->ipcp.compress_cid;
+ break;
case IPCP_OPT_ADDRESS:
/* This is the address he wants in his end */
desiredaddr = p[2] << 24 | p[3] << 16 |
@@ -2917,6 +3034,9 @@ sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
if (debug)
log(-1, " %s ", sppp_ipcp_opt_name(*p));
switch (*p) {
+ case IPCP_OPT_COMPRESSION:
+ sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESSION);
+ break;
case IPCP_OPT_ADDRESS:
/*
* Peer doesn't grok address option. This is
@@ -2943,6 +3063,7 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
u_char *buf, *p;
struct ifnet *ifp = &sp->pp_if;
int debug = ifp->if_flags & IFF_DEBUG;
+ int desiredcomp;
u_long wantaddr;
len -= 4;
@@ -2959,6 +3080,23 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
if (debug)
log(-1, " %s ", sppp_ipcp_opt_name(*p));
switch (*p) {
+ case IPCP_OPT_COMPRESSION:
+ if (len >= 6 && p[1] == 6) {
+ desiredcomp = p[2] << 8 | p[3];
+ if (debug)
+ log(-1, "[wantcomp %#04x] ",
+ desiredcomp);
+ if (desiredcomp == IPCP_COMP_VJ) {
+ sl_compress_init(&sp->pp_comp, p[4]);
+ sp->ipcp.max_state = p[4];
+ sp->ipcp.compress_cid = p[5];
+ if (debug)
+ log(-1, "[agree] ");
+ } else
+ sp->ipcp.opts &=
+ ~(1 << IPCP_OPT_COMPRESSION);
+ }
+ break;
case IPCP_OPT_ADDRESS:
/*
* Peer doesn't like our local IP address. See
@@ -3031,6 +3169,14 @@ sppp_ipcp_scr(struct sppp *sp)
u_long ouraddr;
int i = 0;
+ if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
+ opt[i++] = IPCP_OPT_COMPRESSION;
+ opt[i++] = 6;
+ opt[i++] = IPCP_COMP_VJ >> 8;
+ opt[i++] = IPCP_COMP_VJ;
+ opt[i++] = sp->ipcp.max_state;
+ opt[i++] = sp->ipcp.compress_cid;
+ }
if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
sppp_get_ip_addrs(sp, &ouraddr, 0, 0);
opt[i++] = IPCP_OPT_ADDRESS;
@@ -4858,6 +5004,8 @@ sppp_params(struct sppp *sp, u_long cmd, void *data)
bcopy(spr.defs.hisauth.secret, sp->hisauth.secret,
AUTHKEYLEN);
}
+ /* set VJ enable flag */
+ sp->enable_vj = spr.defs.enable_vj;
break;
default:
OpenPOWER on IntegriCloud