sndcp: Initial libosmo-gprs-sndcp support

This commit follows a similar approach to Change-Id
I588eb576b2703262f4ab9566ec362920d8390cfd, this time targeting the SNDCP
layer, creating a new library for it.
This new library depends on headers from libosmo-gprs-llc since the
SNDCP spec takes the interface towards lower interfaces from same
llc_prim. It doesn't really call any API from the libosmo-gprs-llc
library to dispatch the primitive, that's left for the application, so
that it can be reused against other implementations.

Most of the SNDCP data structures and APIs are kept private and used
only internally. The Higher/lower layers are expected to interact with
it through the sndcp_prim API.

This commit also implements some of the code paths of the public API by
means on importing SNDCP code from osmo-sgsn.git commit
57b63875c762a784127a13becd1c2549ca6c5454.
The import of code cannot be done in a separate commit since existing code
in osmo-sgsn.git is low quality and has tons of layer violations in all
directions.
Hence, this commit aims at being an initial point of having some working
SNDCP stack by means of a few unit tests, but by no means aims to be a
total working implementation. Some code paths are missing; bugs are
expected at this point.

Change-Id: Ie05b5d721cf0a6147ed45c1feb75ad829865252b
changes/90/30490/15
Pau Espin 2022-12-05 14:01:36 +01:00 committed by pespin
parent fc11417ce6
commit 24a100bac8
40 changed files with 8774 additions and 9 deletions

View File

@ -5,3 +5,8 @@
--exclude ^src/rlcmac/ts_44_018.c$
--exclude ^src/rlcmac/ts_44_060.c$
--exclude ^include/osmocom/gprs/rlcmac/gprs_rlcmac.h$
--exclude ^include/osmocom/gprs/sndcp/v42bis_private.h$
--exclude ^include/osmocom/gprs/sndcp/v42bis.h$
--exclude ^src/sndcp/v42bis.c$
--exclude ^include/osmocom/gprs/sndcp/slhc.h$
--exclude ^src/sndcp/slhc.c$

View File

@ -17,6 +17,7 @@ pkgconfig_DATA = \
libosmo-csn1.pc \
libosmo-gprs-llc.pc \
libosmo-gprs-rlcmac.pc \
libosmo-gprs-sndcp.pc \
$(NULL)
BUILT_SOURCES = $(top_srcdir)/.version

View File

@ -77,19 +77,23 @@ AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([libosmo-csn1.pc
libosmo-gprs-llc.pc
libosmo-gprs-rlcmac.pc
libosmo-gprs-sndcp.pc
include/Makefile
include/osmocom/Makefile
include/osmocom/csn1/Makefile
include/osmocom/gprs/Makefile
include/osmocom/gprs/llc/Makefile
include/osmocom/gprs/rlcmac/Makefile
include/osmocom/gprs/sndcp/Makefile
src/Makefile
src/csn1/Makefile
src/llc/Makefile
src/rlcmac/Makefile
src/sndcp/Makefile
tests/Makefile
tests/llc/Makefile
tests/rlcmac/Makefile
tests/sndcp/Makefile
Makefile
contrib/libosmo-gprs.spec])
AC_OUTPUT

View File

@ -78,6 +78,23 @@ Requires: libosmo-csn1-devel = %{version}
This package provides development files for compiling a program using
libosmo-gprs-rlcmac - RLC/MAC protocol definitions for (E)GPRS.
%package -n libosmo-gprs-sndcp0
Summary: Osmocom GPRS SNDCP library
License: AGPL-3.0-or-later
Group: System/Libraries
%description -n libosmo-gprs-sndcp0
This package provides SNDCP (Subnetwork Dependent Convergence Protocol) layer for (E)GPRS.
%package -n libosmo-gprs-sndcp-devel
Summary: Development files for libosmo-gprs-sndcp
License: AGPL-3.0-or-later
Group: Development/Libraries/C and C++
Requires: libosmo-gprs-sndcp0 = %{version}
%description -n libosmo-gprs-sndcp-devel
This package provides development files for compiling a program using
libosmo-gprs-sndcp - SNDCP (Subnetwork Dependent Convergence Protocol) layer for (E)GPRS.
%prep
%setup -q
@ -101,6 +118,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%postun -n libosmo-gprs-llc0 -p /sbin/ldconfig
%post -n libosmo-gprs-rlcmac0 -p /sbin/ldconfig
%postun -n libosmo-gprs-rlcmac0 -p /sbin/ldconfig
%post -n libosmo-gprs-sndcp0 -p /sbin/ldconfig
%postun -n libosmo-gprs-sndcp0 -p /sbin/ldconfig
%files -n libosmo-csn1-0
%_libdir/libosmo-csn1.so.0*
@ -134,4 +153,15 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%_libdir/libosmo-gprs-rlcmac.so
%_libdir/pkgconfig/libosmo-gprs-rlcmac.pc
%files -n libosmo-gprs-sndcp0
%_libdir/libosmo-gprs-sndcp.so.0*
%files -n libosmo-gprs-sndcp-devel
%dir %_includedir/%name
%dir %_includedir/%name/osmocom
%dir %_includedir/%name/osmocom/gprs
%_includedir/%name/osmocom/gprs/sndcp
%_libdir/libosmo-gprs-sndcp.so
%_libdir/pkgconfig/libosmo-gprs-sndcp.pc
%changelog

25
debian/control vendored
View File

@ -92,3 +92,28 @@ Section: libdevel
Depends: libosmo-gprs-rlcmac0 (= ${binary:Version}),
${misc:Depends}
Description: Development headers and libraries for libosmo-gprs-rlcmac
Package: libosmo-gprs-sndcp0
Section: libs
Architecture: any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends},
${shlibs:Depends}
Description: Osmocom SNDCP (Subnetwork Dependent Convergence Protocol) layer for GPRS and EGPRS
Package: libosmo-gprs-sndcp-dbg
Architecture: any
Section: debug
Multi-Arch: same
Depends: libosmo-gprs-sndcp0 (= ${binary:Version}),
${misc:Depends}
Description: Debug symbols for libosmo-gprs-sndcp
Package: libosmo-gprs-sndcp-dev
Architecture: any
Multi-Arch: same
Section: libdevel
Depends: libosmo-gprs-sndcp0 (= ${binary:Version}),
${misc:Depends}
Description: Development headers and libraries for libosmo-gprs-sndcp

View File

@ -1,4 +1,5 @@
SUBDIRS = \
llc \
rlcmac \
sndcp \
$(NULL)

View File

@ -252,15 +252,6 @@ struct gprs_llc_llme {
uint16_t nsei;
struct gprs_llc_lle lle[NUM_SAPIS];
/* Compression entities */
struct {
/* In these two list_heads we will store the
* data and protocol compression entities,
* together with their compression states */
struct llist_head *proto;
struct llist_head *data;
} comp;
/* Internal management */
uint32_t age_timestamp;
};

View File

@ -0,0 +1,18 @@
noinst_HEADERS = \
comp.h \
dcomp.h \
pcomp.h \
slhc.h \
sndcp_private.h \
xid.h \
v42bis.h \
v42bis_private.h \
$(NULL)
sndcp_HEADERS = \
sndcp.h \
sndcp_prim.h \
$(NULL)
sndcpdir = $(includedir)/osmocom/gprs/sndcp

View File

@ -0,0 +1,82 @@
/* GPRS SNDCP header compression entity management tools */
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/gprs/sndcp/xid.h>
/* Header / Data compression entity */
struct gprs_sndcp_comp {
struct llist_head list;
/* Serves as an ID in case we want to delete this entity later */
unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */
/* Specifies to which NSAPIs the compression entity is assigned */
uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */
uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
/* Assigned pcomp values */
uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */
uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */
/* Algorithm parameters */
union gprs_sndcp_comp_algo algo;
enum gprs_sndcp_xid_param_types compclass; /* See gprs_sndcp_xid.h/c */
void *state; /* Algorithm status and parameters */
};
#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */
#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */
/* Allocate a compression enitiy list */
struct llist_head *gprs_sndcp_comp_alloc(const void *ctx);
/* Free a compression entitiy list */
void gprs_sndcp_comp_free(struct llist_head *comp_entities);
/* Delete a compression entity */
void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity);
/* Create and Add a new compression entity
* (returns a pointer to the compression entity that has just been created) */
struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx,
struct llist_head *comp_entities,
const struct gprs_sndcp_comp_field
*comp_field);
/* Find which compression entity handles the specified pcomp/dcomp */
struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head
*comp_entities, uint8_t comp);
/* Find which compression entity handles the specified nsapi */
struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head
*comp_entities, uint8_t nsapi);
/* Find a comp_index for a given pcomp/dcomp value */
uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity,
uint8_t comp);
/* Find a pcomp/dcomp value for a given comp_index */
uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity,
uint8_t comp_index);

View File

@ -0,0 +1,53 @@
/* GPRS SNDCP data compression handler */
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/gprs/sndcp/comp.h>
/* Note: The decompressed packet may have a maximum size of:
* Return value * MAX_DATADECOMPR_FAC */
#define MAX_DATADECOMPR_FAC 10
/* Note: In unacknowledged mode (SN_UNITDATA), the compression state is reset
* for every NPDU. The compressor needs a reasonably large payload to operate
* effectively (yield positive compression gain). For packets shorter than 100
* byte, no positive compression gain can be expected so we will skip the
* compression for short packets. */
#define MIN_COMPR_PAYLOAD 100
/* Initialize data compression */
int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity,
const struct gprs_sndcp_comp_field *comp_field);
/* Terminate data compression */
void gprs_sndcp_dcomp_term(struct gprs_sndcp_comp *comp_entity);
/* Expand packet */
int gprs_sndcp_dcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp,
const struct llist_head *comp_entities);
/* Compress packet */
int gprs_sndcp_dcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp,
const struct llist_head *comp_entities,
uint8_t nsapi);

View File

@ -0,0 +1,46 @@
/* GPRS SNDCP header compression handler */
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/gprs/sndcp/comp.h>
/* Note: The decompressed packet may have a maximum size of:
* Return value + MAX_DECOMPR_INCR */
#define MAX_HDRDECOMPR_INCR 64
/* Initialize header compression */
int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity,
const struct gprs_sndcp_comp_field *comp_field);
/* Terminate header compression */
void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity);
/* Expand packet header */
int gprs_sndcp_pcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp,
const struct llist_head *comp_entities);
/* Compress packet header */
int gprs_sndcp_pcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp,
const struct llist_head *comp_entities,
uint8_t nsapi);

View File

@ -0,0 +1,187 @@
#ifndef _SLHC_H
#define _SLHC_H
/*
* Definitions for tcp compression routines.
*
* $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $
*
* Copyright (c) 1989 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
* - Initial distribution.
*
*
* modified for KA9Q Internet Software Package by
* Katie Stevens (dkstevens@ucdavis.edu)
* University of California, Davis
* Computing Services
* - 01-31-90 initial adaptation
*
* - Feb 1991 Bill_Simpson@um.cc.umich.edu
* variable number of conversation slots
* allow zero or one slots
* separate routines
* status display
*/
/*
* Compressed packet format:
*
* The first octet contains the packet type (top 3 bits), TCP
* 'push' bit, and flags that indicate which of the 4 TCP sequence
* numbers have changed (bottom 5 bits). The next octet is a
* conversation number that associates a saved IP/TCP header with
* the compressed packet. The next two octets are the TCP checksum
* from the original datagram. The next 0 to 15 octets are
* sequence number changes, one change per bit set in the header
* (there may be no changes and there are two special cases where
* the receiver implicitly knows what changed -- see below).
*
* There are 5 numbers which can change (they are always inserted
* in the following order): TCP urgent pointer, window,
* acknowledgment, sequence number and IP ID. (The urgent pointer
* is different from the others in that its value is sent, not the
* change in value.) Since typical use of SLIP links is biased
* toward small packets (see comments on MTU/MSS below), changes
* use a variable length coding with one octet for numbers in the
* range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
* range 256 - 65535 or 0. (If the change in sequence number or
* ack is more than 65535, an uncompressed packet is sent.)
*/
/*
* Packet types (must not conflict with IP protocol version)
*
* The top nibble of the first octet is the packet type. There are
* three possible types: IP (not proto TCP or tcp with one of the
* control flags set); uncompressed TCP (a normal IP/TCP packet but
* with the 8-bit protocol field replaced by an 8-bit connection id --
* this type of packet syncs the sender & receiver); and compressed
* TCP (described above).
*
* LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
* is logically part of the 4-bit "changes" field that follows. Top
* three bits are actual packet type. For backward compatibility
* and in the interest of conserving bits, numbers are chosen so the
* IP protocol version number (4) which normally appears in this nibble
* means "IP packet".
*/
#include <linux/ip.h>
#include <linux/tcp.h>
/* SLIP compression masks for len/vers byte */
#define SL_TYPE_IP 0x40
#define SL_TYPE_UNCOMPRESSED_TCP 0x70
#define SL_TYPE_COMPRESSED_TCP 0x80
#define SL_TYPE_ERROR 0x00
/* Bits in first octet of compressed packet */
#define NEW_C 0x40 /* flag bits for what changed in a packet */
#define NEW_I 0x20
#define NEW_S 0x08
#define NEW_A 0x04
#define NEW_W 0x02
#define NEW_U 0x01
/* reserved, special-case values of above */
#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
#define TCP_PUSH_BIT 0x10
/*
* data type and sizes conversion assumptions:
*
* VJ code KA9Q style generic
* u_char byte_t unsigned char 8 bits
* u_short int16 unsigned short 16 bits
* u_int int16 unsigned short 16 bits
* u_long unsigned long unsigned long 32 bits
* int int32 long 32 bits
*/
typedef __u8 byte_t;
typedef __u32 int32;
/*
* "state" data for each active tcp conversation on the wire. This is
* basically a copy of the entire IP/TCP header from the last packet
* we saw from the conversation together with a small identifier
* the transmit & receive ends of the line use to locate saved header.
*/
struct cstate {
byte_t cs_this; /* connection id number (xmit) */
struct cstate *next; /* next in ring (xmit) */
struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */
struct tcphdr cs_tcp;
unsigned char cs_ipopt[64];
unsigned char cs_tcpopt[64];
int cs_hsize;
};
#define NULLSLSTATE (struct cstate *)0
/*
* all the state data for one serial line (we need one of these per line).
*/
struct slcompress {
struct cstate *tstate; /* transmit connection states (array)*/
struct cstate *rstate; /* receive connection states (array)*/
byte_t tslot_limit; /* highest transmit slot id (0-l)*/
byte_t rslot_limit; /* highest receive slot id (0-l)*/
byte_t xmit_oldest; /* oldest xmit in ring */
byte_t xmit_current; /* most recent xmit id */
byte_t recv_current; /* most recent rcvd id */
byte_t flags;
#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */
int32 sls_o_nontcp; /* outbound non-TCP packets */
int32 sls_o_tcp; /* outbound TCP packets */
int32 sls_o_uncompressed; /* outbound uncompressed packets */
int32 sls_o_compressed; /* outbound compressed packets */
int32 sls_o_searches; /* searches for connection state */
int32 sls_o_misses; /* times couldn't find conn. state */
int32 sls_i_uncompressed; /* inbound uncompressed packets */
int32 sls_i_compressed; /* inbound compressed packets */
int32 sls_i_error; /* inbound error packets */
int32 sls_i_tossed; /* inbound packets tossed because of error */
int32 sls_i_runt;
int32 sls_i_badcheck;
};
#define NULLSLCOMPR (struct slcompress *)0
/* In slhc.c: */
struct slcompress *slhc_init(const void *ctx, int rslots, int tslots);
void slhc_free(struct slcompress *comp);
int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
unsigned char *ocp, unsigned char **cpp, int compress_cid);
int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize);
int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize);
int slhc_toss(struct slcompress *comp);
void slhc_i_status(struct slcompress *comp);
void slhc_o_status(struct slcompress *comp);
#endif /* _SLHC_H */

View File

@ -0,0 +1,16 @@
#pragma once
/* Subnetwork Dependent Convergence Protocol (SNDCP) definitions from 3GPP TS 44.065 */
#include <stdint.h>
#include <stddef.h>
int osmo_gprs_sndcp_init(void);
enum osmo_gprs_sndcp_log_cat {
OSMO_GPRS_SNDCP_LOGC_SNDCP,
OSMO_GPRS_SNDCP_LOGC_SLHC,
_OSMO_GPRS_SNDCP_LOGC_MAX,
};
void osmo_gprs_sndcp_set_log_cat(enum osmo_gprs_sndcp_log_cat logc, int logc_num);

View File

@ -0,0 +1,212 @@
#pragma once
/* 3GPP TS 44.065, section 5 "Service primitives and functions" */
#include <stdint.h>
#include <stddef.h>
#include <osmocom/core/prim.h>
#include <osmocom/gsm/gsm0808_utils.h>
#include <osmocom/gprs/sndcp/sndcp.h>
struct osmo_gprs_llc_prim;
/* Section 5.1 "Service primitives" */
enum osmo_gprs_sndcp_prim_sap {
OSMO_GPRS_SNDCP_SAP_SN,
OSMO_GPRS_SNDCP_SAP_SNSM,
};
extern const struct value_string osmo_gprs_sndcp_prim_sap_names[];
static inline const char *osmo_gprs_sndcp_prim_sap_name(enum osmo_gprs_sndcp_prim_sap val)
{
return get_value_string(osmo_gprs_sndcp_prim_sap_names, val);
}
/* Table 1: SNDCP layer service primitives */
enum osmo_gprs_sndcp_sn_prim_type {
OSMO_GPRS_SNDCP_SN_DATA, /* Req/Ind: N-PDU, NSAPI, N-PDU Number*/
OSMO_GPRS_SNDCP_SN_UNITDATA, /* Req/Ind: N-PDU, NSAPI */
OSMO_GPRS_SNDCP_SN_XID, /* Req/Ind/Resp/Cnf: Req/Neg SNDCP XID Parameters */
};
extern const struct value_string osmo_gprs_sndcp_sn_prim_type_names[];
static inline const char *osmo_gprs_sndcp_sn_prim_type_name(enum osmo_gprs_sndcp_sn_prim_type val)
{
return get_value_string(osmo_gprs_sndcp_sn_prim_type_names, val);
}
/* Table 2: Service primitives used by the SNDCP entity */
enum osmo_gprs_sndcp_snsm_prim_type {
OSMO_GPRS_SNDCP_SNSM_ACTIVATE, /* Ind/Resp: TLLI, NSAPI, QoS profile, SAPI, Radio Priority */
OSMO_GPRS_SNDCP_SNSM_DEACTIVATE, /* Ind/Resp: TLLI, NSAPI(s), LLC Release Indicator, XID Negotiation Indicator */
OSMO_GPRS_SNDCP_SNSM_MODIFY, /* Ind/Resp: TLLI, NSAPI, QoS Profile, SAPI, Radio Priority, Send N-PDU Number, Receive N-PDU Number */
OSMO_GPRS_SNDCP_SNSM_STATUS, /* Req: TLLI, SAPI, Cause */
OSMO_GPRS_SNDCP_SNSM_SEQUENCE, /* Ind/Resp: TLLI, NSAPI, Receive N-PDU Number */
OSMO_GPRS_SNDCP_SNSM_STOP_ASSIGN, /* Ind/Resp: TLLI, NSAPI */
};
extern const struct value_string osmo_gprs_sndcp_snsm_prim_type_names[];
static inline const char *osmo_gprs_sndcp_snsm_prim_type_name(enum osmo_gprs_sndcp_snsm_prim_type val)
{
return get_value_string(osmo_gprs_sndcp_snsm_prim_type_names, val);
}
/* Parameters for OSMO_GPRS_SNDCP_SN_* prims */
struct osmo_gprs_sndcp_sn_prim {
/* Common fields */
uint32_t tlli;
uint8_t sapi; /* llc */
/* Specific fields */
union {
/* OSMO_GPRS_SNDCP_SN_DATA | Req */
struct {
uint8_t nsapi;
uint8_t *npdu;
size_t npdu_len;
uint32_t npdu_number;
} data_req;
/* OSMO_GPRS_SNDCP_SN_DATA | Ind */
struct {
uint8_t nsapi;
uint8_t *npdu;
size_t npdu_len;
} data_ind;
/* OSMO_GPRS_SNDCP_SN_UNITDATA | Req */
struct {
uint8_t nsapi;
uint8_t *npdu;
size_t npdu_len;
} unitdata_req;
/* OSMO_GPRS_SNDCP_SN_UNITDATA | Ind */
struct {
uint8_t nsapi;
uint8_t *npdu;
size_t npdu_len;
} unitdata_ind;
/* OSMO_GPRS_SNDCP_SN_XID | Req */
struct {
uint8_t nsapi;
struct {
bool active;
bool passive;
int s01;
} pcomp_rfc1144;
struct {
bool active;
bool passive;
int p0;
int p1;
int p2;
} dcomp_v42bis;
} xid_req;
/* OSMO_GPRS_SNDCP_SN_XID | Ind */
struct {
uint8_t *req_xid;
uint32_t req_xid_len;
} xid_ind;
/* OSMO_GPRS_SNDCP_SN_XID | Rsp */
struct {
uint8_t nsapi;
} xid_rsp;
/* OSMO_GPRS_SNDCP_SN_XID | Cnf */
struct {
uint8_t *neg_xid;
uint32_t neg_xid_len;
} xid_cnf;
};
};
/* Parameters for OSMO_GPRS_SNDCP_SNSM_* prims */
struct osmo_gprs_sndcp_snsm_prim {
/* Common fields */
uint32_t tlli;
/* Specific fields */
union {
/* OSMO_GPRS_SNDCP_SNSM_ACTIVATE | Ind */
struct {
uint8_t nsapi;
uint8_t sapi;
uint8_t qos_params[3];
uint8_t radio_prio;
} activate_ind;
/* OSMO_GPRS_SNDCP_SNSM_ACTIVATE | Rsp */
struct {
uint8_t nsapi;
} activate_rsp;
/* OSMO_GPRS_SNDCP_SNSM_DEACTIVATE | Req */
struct {
uint8_t nsapi;
/* TODO: LLC Release Indicator,
XID Negotiation Indicator
*/
} deactivate_ind;
/* OSMO_GPRS_SNDCP_SNSM_DEACTIVATE | Rsp */
struct {
uint8_t nsapi;
} deactivate_rsp;
/* OSMO_GPRS_SNDCP_SNSM_MODIFY | Ind */
struct {
uint8_t nsapi;
uint8_t sapi;
uint8_t qos_params[3];
uint8_t radio_prio;
unsigned int tx_npdu_nr;
unsigned int rx_npdu_nr;
} modify_ind;
/* OSMO_GPRS_SNDCP_SNSM_MODIFY | Rsp */
struct {
uint8_t nsapi;
} modify_rsp;
/* OSMO_GPRS_SNDCP_SNSM_STATUS| Req */
struct {
uint8_t sapi;
uint8_t cause;
} status_req;
/* OSMO_GPRS_SNDCP_SNSM_SEQUENCE | Ind */
struct {
uint8_t nsapi;
unsigned int rx_npdu_nr;
} sequence_ind;
/* OSMO_GPRS_SNDCP_SNSM_SEQUENCE | Rsp */
struct {
uint8_t nsapi;
} sequence_rsp;
/* OSMO_GPRS_SNDCP_SNSM_STOP_ASSIGN | Ind */
struct {
uint8_t nsapi;
} stop_assign_ind;
};
};
struct osmo_gprs_sndcp_prim {
struct osmo_prim_hdr oph;
union {
struct osmo_gprs_sndcp_sn_prim sn;
struct osmo_gprs_sndcp_snsm_prim snsm;
};
};
typedef int (*osmo_gprs_sndcp_prim_up_cb)(struct osmo_gprs_sndcp_prim *sndcp_prim, void *up_user_data);
void osmo_gprs_sndcp_prim_set_up_cb(osmo_gprs_sndcp_prim_up_cb up_cb, void *up_user_data);
typedef int (*osmo_gprs_sndcp_prim_down_cb)(struct osmo_gprs_llc_prim *llc_prim, void *down_user_data);
void osmo_gprs_sndcp_prim_set_down_cb(osmo_gprs_sndcp_prim_down_cb down_cb, void *down_user_data);
typedef int (*osmo_gprs_sndcp_prim_snsm_cb)(struct osmo_gprs_sndcp_prim *sndcp_prim, void *snsm_user_data);
void osmo_gprs_sndcp_prim_set_snsm_cb(osmo_gprs_sndcp_prim_snsm_cb snsm_cb, void *snsm_user_data);
int osmo_gprs_sndcp_prim_upper_down(struct osmo_gprs_sndcp_prim *sndcp_prim);
int osmo_gprs_sndcp_prim_lower_up(struct osmo_gprs_llc_prim *llc_prim);
int osmo_gprs_sndcp_prim_dispatch_snsm(struct osmo_gprs_sndcp_prim *sndcp_prim);
const char *osmo_gprs_sndcp_prim_name(const struct osmo_gprs_sndcp_prim *sndcp_prim);
/* Alloc primitive for SN SAP: */
struct osmo_gprs_sndcp_prim *osmo_gprs_sndcp_prim_alloc_sn_data_req(uint32_t tlli, uint8_t sapi, uint8_t nsapi, uint8_t *npdu, size_t npdu_len);
struct osmo_gprs_sndcp_prim *osmo_gprs_sndcp_prim_alloc_sn_unitdata_req(uint32_t tlli, uint8_t sapi, uint8_t nsapi, uint8_t *npdu, size_t npdu_len);
struct osmo_gprs_sndcp_prim *osmo_gprs_sndcp_prim_alloc_sn_xid_req(uint32_t tlli, uint8_t sapi, uint8_t nsapi);
struct osmo_gprs_sndcp_prim *osmo_gprs_sndcp_prim_alloc_sn_xid_rsp(uint32_t tlli, uint8_t sapi, uint8_t nsapi);
/* Alloc primitive for SNSM SAP: */
struct osmo_gprs_sndcp_prim *osmo_gprs_sndcp_prim_alloc_snsm_activate_ind(uint32_t tlli, uint8_t nsapi, uint8_t sapi);
struct osmo_gprs_sndcp_prim *osmo_gprs_sndcp_prim_alloc_snsm_deactivate_ind(uint32_t tlli, uint8_t nsapi);

View File

@ -0,0 +1,220 @@
#pragma once
/* 3GPP TS 44.065, private header */
#include <stdint.h>
#include <stddef.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/logging.h>
#include <osmocom/gprs/llc/llc.h>
#include <osmocom/gprs/sndcp/sndcp.h>
#include <osmocom/gprs/sndcp/sndcp_prim.h>
#include <osmocom/gprs/sndcp/comp.h>
#include <osmocom/gprs/sndcp/pcomp.h>
#include <osmocom/gprs/sndcp/dcomp.h>
extern int g_sndcp_log_cat[_OSMO_GPRS_SNDCP_LOGC_MAX];
#define LOGSNDCP(lvl, fmt, args...) LOGP(g_sndcp_log_cat[OSMO_GPRS_SNDCP_LOGC_SNDCP], lvl, fmt, ## args)
#define msgb_sndcp_prim(msg) ((struct osmo_gprs_sndcp_prim *)(msg)->l1h)
/* Chapter 7.2: SN-PDU Formats */
struct sndcp_common_hdr {
#if OSMO_IS_LITTLE_ENDIAN
/* octet 1 */
uint8_t nsapi:4;
uint8_t more:1;
uint8_t type:1;
uint8_t first:1;
uint8_t spare:1;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
uint8_t spare:1, first:1, type:1, more:1, nsapi:4;
#endif
} __attribute__((packed));
/* PCOMP / DCOMP only exist in first fragment */
struct sndcp_comp_hdr {
#if OSMO_IS_LITTLE_ENDIAN
/* octet 2 */
uint8_t pcomp:4;
uint8_t dcomp:4;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
uint8_t dcomp:4, pcomp:4;
#endif
} __attribute__((packed));
struct sndcp_udata_hdr {
#if OSMO_IS_LITTLE_ENDIAN
/* octet 3 */
uint8_t npdu_high:4;
uint8_t seg_nr:4;
/* octet 4 */
uint8_t npdu_low;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
uint8_t seg_nr:4, npdu_high:4;
uint8_t npdu_low;
#endif
} __attribute__((packed));
/* A fragment queue entry, containing one framgent of a N-PDU */
struct defrag_queue_entry {
struct llist_head list;
/* segment number of this fragment */
uint32_t seg_nr;
/* length of the data area of this fragment */
uint32_t data_len;
/* pointer to the data of this fragment */
uint8_t *data;
};
/* TODO: this needs to be set through API or VTY: */
struct gprs_sndcp_ctx_cfg {
bool pcomp_rfc1144_passive_accept;
bool dcomp_v42bis_passive_accept;
};
struct gprs_sndcp_ctx {
osmo_gprs_sndcp_prim_up_cb sndcp_up_cb;
void *sndcp_up_cb_user_data;
osmo_gprs_sndcp_prim_down_cb sndcp_down_cb;
void *sndcp_down_cb_user_data;
osmo_gprs_sndcp_prim_snsm_cb sndcp_snsm_cb;
void *sndcp_snsm_cb_user_data;
struct llist_head snme_list; /* list of struct gprs_sndcp_mgmt_entity->list */
struct gprs_sndcp_ctx_cfg cfg;
};
extern struct gprs_sndcp_ctx *g_ctx;
/* A fragment queue header, maintaining list of fragments for one N-PDU */
struct gprs_sndcp_defrag_state {
/* PDU number for which the defragmentation state applies */
uint16_t npdu;
/* highest segment number we have received so far */
uint8_t highest_seg;
/* bitmask of the segments we already have */
uint32_t seg_have;
/* do we still expect more segments? */
unsigned int no_more;
/* total length of all segments together */
unsigned int tot_len;
/* linked list of defrag_queue_entry: one for each fragment */
struct llist_head frag_list;
struct osmo_timer_list timer;
/* Holds state to know which compression mode is used
* when the packet is re-assembled */
uint8_t pcomp;
uint8_t dcomp;
/* Holds the pointers to the compression entity list
* that is used when the re-assembled packet is decompressed */
struct llist_head *proto;
struct llist_head *data;
};
/* See 6.7.1.2 Reassembly */
enum gprs_sndcp_rx_state {
GPRS_SNDCP_RX_S_FIRST,
GPRS_SNDCP_RX_S_SUBSEQ,
GPRS_SNDCP_RX_S_DISCARD,
};
#define GPRS_SNDCP_NUM_NSAPIS 16
/* SNDCP entity: One per TLLI + NSAPI */
struct gprs_sndcp_mgmt_entity;
struct gprs_sndcp_entity {
struct gprs_sndcp_mgmt_entity *snme; /* backpointer */
/* FIXME: move this RA_ID up to the LLME or even higher */
//struct gprs_ra_id ra_id;
/* reference to the LLC Entity below this SNDCP entity */
uint8_t llc_sapi;
/* The NSAPI we shall use on top of LLC */
uint8_t nsapi;
/* NPDU number for the GTP->SNDCP side */
uint16_t tx_npdu_nr;
/* SNDCP eeceiver state */
enum gprs_sndcp_rx_state rx_state;
/* The defragmentation queue */
struct gprs_sndcp_defrag_state defrag;
/* Copy of the XID fields array we have sent with the last
* originated XID-Request. NULL if not existing (and l3xid_req_len = 0) */
uint8_t *l3xid_req;
unsigned int l3xid_req_len;
/* TODO: taken from lle.params and not yet set ever in code! */
uint16_t n201_u;
uint16_t n201_i;
};
/* SNDCP management entity: One per TLLI */
struct gprs_sndcp_mgmt_entity {
struct llist_head list; /* item in (struct gprs_sndcp_ctx)->snme_list */
uint32_t tlli;
struct gprs_sndcp_entity *sne[GPRS_SNDCP_NUM_NSAPIS];
/* Compression entities */
struct {
/* In these two list_heads we will store the
* data and protocol compression entities,
* together with their compression states */
struct llist_head *proto;
struct llist_head *data;
} comp;
};
static inline struct gprs_sndcp_entity *gprs_sndcp_snme_get_sne(struct gprs_sndcp_mgmt_entity *snme,
uint8_t nsapi) {
OSMO_ASSERT(nsapi < GPRS_SNDCP_NUM_NSAPIS);
return snme->sne[nsapi];
}
/* sndcp_prim.c: */
struct osmo_gprs_sndcp_prim *gprs_sndcp_prim_alloc_sn_unitdata_ind(uint32_t tlli, uint8_t sapi, uint8_t nsapi, uint8_t *npdu, size_t npdu_len);
struct osmo_gprs_sndcp_prim *gprs_sndcp_prim_alloc_snsm_activate_rsp(uint32_t tlli, uint8_t nsapi);
int gprs_sndcp_prim_call_up_cb(struct osmo_gprs_sndcp_prim *sndcp_prim);
int gprs_sndcp_prim_call_down_cb(struct osmo_gprs_llc_prim *llc_prim);
/* sndcp.c: */
struct gprs_sndcp_mgmt_entity *gprs_sndcp_snme_alloc(uint32_t tlli);
struct gprs_sndcp_mgmt_entity *gprs_sndcp_snme_find_by_tlli(uint32_t tlli);
struct gprs_sndcp_entity *gprs_sndcp_sne_alloc(struct gprs_sndcp_mgmt_entity *snme, uint8_t llc_sapi, uint8_t nsapi);
void gprs_sndcp_sne_free(struct gprs_sndcp_entity *sne);
struct gprs_sndcp_entity *gprs_sndcp_sne_by_dlci_nsapi(uint32_t tlli, uint8_t llc_sapi, uint8_t nsapi);
int gprs_sndcp_sne_handle_llc_ll_unitdata_ind(struct gprs_sndcp_entity *sne,
struct sndcp_common_hdr *sch, uint16_t len);
int gprs_sndcp_snme_handle_llc_ll_xid_ind(struct gprs_sndcp_mgmt_entity *snme, uint32_t sapi, uint8_t *l3params, unsigned int l3params_len);
int gprs_sndcp_snme_handle_llc_ll_xid_cnf(struct gprs_sndcp_mgmt_entity *snme, uint32_t sapi, uint8_t *l3params, unsigned int l3params_len);
int gprs_sndcp_sne_handle_sn_unitdata_req(struct gprs_sndcp_entity *sne, uint8_t *npdu, unsigned int npdu_len);
int gprs_sndcp_sne_handle_sn_xid_req(struct gprs_sndcp_entity *sne, const struct osmo_gprs_sndcp_prim *sndcp_prim);
#define LOGSNME(snme, level, fmt, args...) \
LOGSNDCP(level, "SNME(%08x) " fmt, \
(snme)->tlli, \
## args)
#define LOGSNE(sne, level, fmt, args...) \
LOGSNDCP(level, "SNE(%08x,%s,%u) " fmt, \
(sne)->snme->tlli, \
osmo_gprs_llc_sapi_name((sne)->llc_sapi), \
(sne)->nsapi, \
## args)

View File

@ -0,0 +1,141 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* v42bis.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2005, 2011 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
/*! \page v42bis_page V.42bis modem data compression
\section v42bis_page_sec_1 What does it do?
The v.42bis specification defines a data compression scheme, to work in
conjunction with the error correction scheme defined in V.42.
\section v42bis_page_sec_2 How does it work?
*/
#include <stdint.h>
#if !defined(_SPANDSP_V42BIS_H_)
#define _SPANDSP_V42BIS_H_
#define SPAN_DECLARE(x) x
#define V42BIS_MIN_STRING_SIZE 6
#define V42BIS_MAX_STRING_SIZE 250
#define V42BIS_MIN_DICTIONARY_SIZE 512
#define V42BIS_MAX_BITS 12
#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */
#define V42BIS_MAX_OUTPUT_LENGTH 1024
enum {
V42BIS_P0_NEITHER_DIRECTION = 0,
V42BIS_P0_INITIATOR_RESPONDER,
V42BIS_P0_RESPONDER_INITIATOR,
V42BIS_P0_BOTH_DIRECTIONS
};
enum {
V42BIS_COMPRESSION_MODE_DYNAMIC = 0,
V42BIS_COMPRESSION_MODE_ALWAYS,
V42BIS_COMPRESSION_MODE_NEVER
};
typedef void (*put_msg_func_t)(void *user_data, const uint8_t *msg, int len);
/*!
V.42bis compression/decompression descriptor. This defines the working state for a
single instance of V.42bis compress/decompression.
*/
typedef struct v42bis_state_s v42bis_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Compress a block of octets.
\param s The V.42bis context.
\param buf The data to be compressed.
\param len The length of the data buffer.
\return 0 */
SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t buf[], int len);
/*! Flush out any data remaining in a compression buffer.
\param s The V.42bis context.
\return 0 */
SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s);
/*! Decompress a block of octets.
\param s The V.42bis context.
\param buf The data to be decompressed.
\param len The length of the data buffer.
\return 0 */
SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t buf[], int len);
/*! Flush out any data remaining in the decompression buffer.
\param s The V.42bis context.
\return 0 */
SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s);
/*! Set the compression mode.
\param s The V.42bis context.
\param mode One of the V.42bis compression modes -
V42BIS_COMPRESSION_MODE_DYNAMIC,
V42BIS_COMPRESSION_MODE_ALWAYS,
V42BIS_COMPRESSION_MODE_NEVER */
SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode);
/*! Initialise a V.42bis context.
\param s The V.42bis context.
\param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec.
\param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec.
\param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec.
\param encode_handler Encode callback handler.
\param encode_user_data An opaque pointer passed to the encode callback handler.
\param max_encode_len The maximum length that should be passed to the encode handler.
\param decode_handler Decode callback handler.
\param decode_user_data An opaque pointer passed to the decode callback handler.
\param max_decode_len The maximum length that should be passed to the decode handler.
\return The V.42bis context. */
SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx,
v42bis_state_t *s,
int negotiated_p0,
int negotiated_p1,
int negotiated_p2,
put_msg_func_t encode_handler,
void *encode_user_data,
int max_encode_len,
put_msg_func_t decode_handler,
void *decode_user_data,
int max_decode_len);
/*! Release a V.42bis context.
\param s The V.42bis context.
\return 0 if OK */
SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s);
/*! Free a V.42bis context.
\param s The V.42bis context.
\return 0 if OK */
SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,119 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/v42bis.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
#if !defined(_SPANDSP_PRIVATE_V42BIS_H_)
#define _SPANDSP_PRIVATE_V42BIS_H_
/*!
V.42bis dictionary node.
Note that 0 is not a valid node to point to (0 is always a control code), so 0 is used
as a "no such value" marker in this structure.
*/
typedef struct {
/*! \brief The value of the octet represented by the current dictionary node */
uint8_t node_octet;
/*! \brief The parent of this node */
uint16_t parent;
/*! \brief The first child of this node */
uint16_t child;
/*! \brief The next node at the same depth */
uint16_t next;
} v42bis_dict_node_t;
/*!
V.42bis compression or decompression. This defines the working state for a single instance
of V.42bis compression or decompression.
*/
typedef struct {
/*! \brief Compression enabled. */
int v42bis_parm_p0;
/*! \brief Compression mode. */
int compression_mode;
/*! \brief Callback function to handle output data. */
put_msg_func_t handler;
/*! \brief An opaque pointer passed in calls to the data handler. */
void *user_data;
/*! \brief The maximum amount to be passed to the data handler. */
int max_output_len;
/*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
int transparent;
/*! \brief Next empty dictionary entry */
uint16_t v42bis_parm_c1;
/*! \brief Current codeword size */
uint16_t v42bis_parm_c2;
/*! \brief Threshold for codeword size change */
uint16_t v42bis_parm_c3;
/*! \brief The current update point in the dictionary */
uint16_t update_at;
/*! \brief The last entry matched in the dictionary */
uint16_t last_matched;
/*! \brief The last entry added to the dictionary */
uint16_t last_added;
/*! \brief Total number of codewords in the dictionary */
int v42bis_parm_n2;
/*! \brief Maximum permitted string length */
int v42bis_parm_n7;
/*! \brief The dictionary */
v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
/*! \brief The octet string in progress */
uint8_t string[V42BIS_MAX_STRING_SIZE];
/*! \brief The current length of the octet string in progress */
int string_length;
/*! \brief The amount of the octet string in progress which has already
been flushed out of the buffer */
int flushed_length;
/*! \brief Compression performance metric */
uint16_t compression_performance;
/*! \brief Outgoing bit buffer (compression), or incoming bit buffer (decompression) */
uint32_t bit_buffer;
/*! \brief Outgoing bit count (compression), or incoming bit count (decompression) */
int bit_count;
/*! \brief The output composition buffer */
uint8_t output_buf[V42BIS_MAX_OUTPUT_LENGTH];
/*! \brief The length of the contents of the output composition buffer */
int output_octet_count;
/*! \brief The current value of the escape code */
uint8_t escape_code;
/*! \brief TRUE if we just hit an escape code, and are waiting for the following octet */
int escaped;
} v42bis_comp_state_t;
/*!
V.42bis compression/decompression descriptor. This defines the working state for a
single instance of V.42bis compress/decompression.
*/
struct v42bis_state_s {
/*! \brief Compression state. */
v42bis_comp_state_t compress;
/*! \brief Decompression state. */
v42bis_comp_state_t decompress;
/*! \brief Error and flow logging control */
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,224 @@
/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#define DEFAULT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */
#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit
* for compression enitity number */
#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */
#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */
#define MAX_ROHC 16 /* Maximum number of ROHC compression profiles */
/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */
enum gprs_sndcp_hdr_comp_algo {
RFC_1144, /* TCP/IP header compression, see also 6.5.2 */
RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */
ROHC /* Robust Header Compression, see also 6.5.4 */
};
/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */
enum gprs_sndcp_data_comp_algo {
V42BIS, /* V.42bis data compression, see also 6.6.2 */
V44 /* V44 data compression, see also: 6.6.3 */
};
union gprs_sndcp_comp_algo {
enum gprs_sndcp_hdr_comp_algo pcomp;
enum gprs_sndcp_data_comp_algo dcomp;
};
/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control
* information compression field (Figure 7) and 3GPP TS 44.065,
* 6.6.1.1 Format of the data compression field (Figure 9) */
struct gprs_sndcp_comp_field {
struct llist_head list;
/* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */
unsigned int p;
/* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */
unsigned int entity;
/* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */
union gprs_sndcp_comp_algo algo;
/* Number of contained PCOMP / DCOMP values */
uint8_t comp_len;
/* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */
uint8_t comp[MAX_COMP];
/* Note: Only one of the following struct pointers may,
be used. Unused pointers must be set to NULL! */
struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params;
struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params;
struct gprs_sndcp_pcomp_rohc_params *rohc_params;
struct gprs_sndcp_dcomp_v42bis_params *v42bis_params;
struct gprs_sndcp_dcomp_v44_params *v44_params;
};
/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */
enum gprs_sndcp_xid_param_types {
SNDCP_XID_VERSION_NUMBER,
SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */
SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */
SNDCP_XID_INVALID_COMPRESSION /* Not part of the spec; this means we found an invalid value */
};
/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */
struct gprs_sndcp_pcomp_rfc1144_params {
uint8_t nsapi_len; /* Number of applicable NSAPIs
* (default 0) */
uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
int s01; /* (default 15) */
};
/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */
enum gprs_sndcp_pcomp_rfc1144_pcomp {
RFC1144_PCOMP1, /* Uncompressed TCP */
RFC1144_PCOMP2, /* Compressed TCP */
RFC1144_PCOMP_NUM /* Number of pcomp values */
};
/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */
struct gprs_sndcp_pcomp_rfc2507_params {
uint8_t nsapi_len; /* Number of applicable NSAPIs
* (default 0) */
uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
int f_max_period; /* (default 256) */
int f_max_time; /* (default 5) */
int max_header; /* (default 168) */
int tcp_space; /* (default 15) */
int non_tcp_space; /* (default 15) */
};
/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */
enum gprs_sndcp_pcomp_rfc2507_pcomp {
RFC2507_PCOMP1, /* Full Header */
RFC2507_PCOMP2, /* Compressed TCP */
RFC2507_PCOMP3, /* Compressed TCP non delta */
RFC2507_PCOMP4, /* Compressed non TCP */
RFC2507_PCOMP5, /* Context state */
RFC2507_PCOMP_NUM /* Number of pcomp values */
};
/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */
struct gprs_sndcp_pcomp_rohc_params {
uint8_t nsapi_len; /* Number of applicable NSAPIs
* (default 0) */
uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
int max_cid; /* (default 15) */
int max_header; /* (default 168) */
uint8_t profile_len; /* (default 1) */
uint16_t profile[MAX_ROHC]; /* (default 0, ROHC uncompressed) */
};
/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */
enum gprs_sndcp_pcomp_rohc_pcomp {
ROHC_PCOMP1, /* ROHC small CIDs */
ROHC_PCOMP2, /* ROHC large CIDs */
ROHC_PCOMP_NUM /* Number of pcomp values */
};
/* ROHC compression profiles, see also:
http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */
enum gprs_sndcp_xid_rohc_profiles {
ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */
ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */
ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */
ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */
ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */
ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */
ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */
ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */
ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */
ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */
ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */
ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */
ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */
ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */
ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */
ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */
};
/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */
struct gprs_sndcp_dcomp_v42bis_params {
uint8_t nsapi_len; /* Number of applicable NSAPIs
* (default 0) */
uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
int p0; /* (default 3) */
int p1; /* (default 2048) */
int p2; /* (default 20) */
};
/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */
enum gprs_sndcp_dcomp_v42bis_dcomp {
V42BIS_DCOMP1, /* V.42bis enabled */
V42BIS_DCOMP_NUM /* Number of dcomp values */
};
/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */
struct gprs_sndcp_dcomp_v44_params {
uint8_t nsapi_len; /* Number of applicable NSAPIs
* (default 0) */
uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
int c0; /* (default 10000000) */
int p0; /* (default 3) */
int p1t; /* Refer to subclause 6.6.3.1.4 */
int p1r; /* Refer to subclause 6.6.3.1.5 */
int p3t; /* (default 3 x p1t) */
int p3r; /* (default 3 x p1r) */
};
/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */
enum gprs_sndcp_dcomp_v44_dcomp {
V44_DCOMP1, /* Packet method compressed */
V44_DCOMP2, /* Multi packet method compressed */
V44_DCOMP_NUM /* Number of dcomp values */
};
/* Transform a list with compression fields into an SNDCP-XID message (dst) */
int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen,
const struct llist_head *comp_fields, int version);
/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */
struct llist_head *gprs_sndcp_parse_xid(int *version,
const void *ctx,
const uint8_t *src,
unsigned int src_len,
const struct llist_head
*comp_fields_req);
/* Find out to which compression class the specified comp-field belongs
* (header compression or data compression?) */
enum gprs_sndcp_xid_param_types gprs_sndcp_get_compression_class(
const struct gprs_sndcp_comp_field *comp_field);
/* Dump a list with SNDCP-XID fields (Debug) */
void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields,
unsigned int logl);

12
libosmo-gprs-sndcp.pc.in Normal file
View File

@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Osmocom [E]GPRS SNDCP (Subnetwork Dependent Convergence Protocol) Library
Description: C Utility Library
Version: @VERSION@
Requires: libosmocore libosmo-gprs-llc
Libs: -L${libdir} -losmo-gprs-sndcp
Libs.private: -lm -ltalloc
Cflags: -I${includedir}/

View File

@ -2,4 +2,5 @@ SUBDIRS = \
csn1 \
llc \
rlcmac \
sndcp \
$(NULL)

47
src/sndcp/Makefile.am Normal file
View File

@ -0,0 +1,47 @@
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool
# documentation before making any modification
LIBVERSION=0:0:0
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
$(NULL)
AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \