Files
m241Neelima/components/ip_net2-6.9/iprohc/src/iprohc_udp_ip.c
T
2026-07-30 11:19:44 +05:30

2747 lines
85 KiB
C

/* iprohc_udp_ip.c - ROHC UDP IP profile routines */
/*
* Copyright (c) 2013 Wind River Systems, Inc.
*
* The right to copy, distribute or otherwise make use of this software
* may be licensed only pursuant to the terms of an applicable Wind River
* license agreement. No license to Wind River intellectual property rights
* is granted herein. All rights not licensed by Wind River are reserved
* by Wind River.
*/
/*
modification history
--------------------
01s,08aug13,j_y Clean low impact code review defects
01r,30jul13,j_y Clean medium impact code review defects
01q,15may12,ggz Fix for defect WIND00350062
01e,20oct11,ggz Fix for defect WIND00312450
01d,12apr10,ggz Support 64bit
01c,27mar10,ggz Resolve coverity warnings
01b,15mar10,ggz Remove ip code from comp. context creation function
01a,01dec09,ggz Created. Incorporated IP profile source code
*/
/*
****************************************************************************
* DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* CONFIGURATION
****************************************************************************
*/
#include "iprohc_config.h"
/*
****************************************************************************
* INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
/* ipcom */
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#include <ipcom_clib.h>
#include <ipcom_os.h>
#include <ipcom_sysvar.h>
#include <ipcom_err.h>
#include <ipcom_syslog.h>
#include <ipcom_list.h>
#include <ipcom_time.h>
#include <ipnet_timeout.h>
/* iprohc */
#include "iprohc.h"
#include "iprohc_udp_ip.h"
#include "iprohc_format.h"
#include "iprohc_parser.h"
/*
****************************************************************************
* DEFINES
****************************************************************************
*/
IP_EXTERN Iprohc_data iprohc;
/* This is a compile flag, turning on it will build debug message into image */
#undef ROHC_DEBUG
/*
****************************************************************************
* LOCAL TYPES
****************************************************************************
*/
/*
****************************************************************************
* LOCAL Data
****************************************************************************
*/
/*
****************************************************************************
* LOCAL PROTOTYPES
****************************************************************************
*/
/* Compressor functions */
IP_STATIC Ip_err iprohc_udp_c_init(Iprohc_c_udp_context *udp_context);
IP_STATIC Ip_err iprohc_fmt_udp_ip_ir(Iprohc_c_context *context, Ipcom_pkt *pkt);
IP_STATIC Ip_err iprohc_fmt_udp_ip_irdyn(Iprohc_c_context *context, Ipcom_pkt *pkt);
IP_STATIC Ip_err iprohc_fmt_udp_ip_general(Iprohc_c_context *context,
Ipcom_pkt *pkt);
IP_STATIC Ip_err iprohc_udp_c_get_header(Ipcom_pkt *pkt, udp_header *header);
/* De-compressor functions */
IP_STATIC Ip_err iprohc_udp_d_init(Iprohc_d_udp_context *udp_context);
IP_STATIC Ip_err iprohc_decomp_udp_ip_ir(Iprohc_d_context *context,
Ipcom_pkt *pkt, Ip_u8 type_data);
IP_STATIC Ip_err iprohc_decomp_udp_ip_irdyn(Iprohc_d_context *context,
Ipcom_pkt *pkt, Ip_u8 type_data);
IP_STATIC Ip_err iprohc_decomp_udp_ip_general(Iprohc_d_context *context,
Ipcom_pkt *pkt, Ip_u8 pkt_type, Ip_u8 type_data);
IP_STATIC Ip_err
iprohc_d_copy_udp_context(Iprohc_d_udp_context **to_context,
Iprohc_d_udp_context *from_context);
IP_STATIC Ip_err
iprohc_d_udp_ip_crc_validate(Iprohc_d_context *context,
Iprohc_d_ip_context *backup_context,
Iprohc_d_udp_context *backup_udp_context,
Ipcom_pkt *pkt, Ip_u8 pkt_type,
Ip_u8 crc, Ip_u8 crc_bits, int mode, Ip_bool udp_chksum);
IP_STATIC Ip_err iprohc_del_udp_ip_context(void *context, Ip_bool is_comp);
IP_STATIC Ip_err iprohc_del_udp_context(void *context, Ip_bool is_comp);
/*
****************************************************************************
* LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* iprohc_del_udp_ip_context
*===========================================================================
* Description: Delete a UDP_IP profile specific compression/decompression
* context.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_del_udp_ip_context(void *context, Ip_bool is_comp)
{
Ip_err retval = IPCOM_SUCCESS;
void *ip_context, *udp_context;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_del_udp_ip_context\n");
#endif
if(is_comp == IP_TRUE)
{
ip_context = ((Iprohc_c_udp_ip_context *)context)->ip_context;
udp_context = ((Iprohc_c_udp_ip_context *)context)->udp_context;
}
else
{
ip_context = ((Iprohc_d_udp_ip_context *)context)->ip_context;
udp_context = ((Iprohc_d_udp_ip_context *)context)->udp_context;
}
/* Delete ip context */
if(ip_context)
retval = iprohc_del_ip_context(ip_context, is_comp);
/* Delete UDP context */
if(udp_context)
(void) iprohc_del_udp_context(udp_context, is_comp);
return retval;
}
/*
*===========================================================================
* iprohc_d_copy_udp_context
*===========================================================================
* Description: Make a copy of a UDP profile decompression context.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_d_copy_udp_context(Iprohc_d_udp_context **to_context,
Iprohc_d_udp_context *from_context)
{
Ip_err retval = IPCOM_SUCCESS;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_d_copy_udp_context\n") ;
#endif
*to_context = (Iprohc_d_udp_context *)
ipcom_malloc(sizeof(Iprohc_d_udp_context));
if (*to_context == IP_NULL)
{
retval = IPCOM_ERR_NO_MEMORY;
IPCOM_LOG0(ERR,"iprohc_d_copy_udp_context, out of memory(to context)");
}
else
ipcom_memcpy(*to_context, from_context, sizeof(Iprohc_d_udp_context));
return retval;
}
/*
*===========================================================================
* iprohc_d_udp_ip_crc_validate
*===========================================================================
* Description: CRC validation of the re-constructed UDP_IP headers, decompressor
* context state and mode transition, and send out feedbacks.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_d_udp_ip_crc_validate(Iprohc_d_context *context,
Iprohc_d_ip_context *backup_context,
Iprohc_d_udp_context *backup_udp_context,
Ipcom_pkt *pkt, Ip_u8 pkt_type,
Ip_u8 crc, Ip_u8 crc_bits, int mode, Ip_bool udp_chksum)
{
Ip_err retval = IPCOM_SUCCESS;
Iprohc_feedback *feedback = IP_NULL;
Ip_u8 calc_crc = 0;
Iprohc_d_udp_context *udp_context;
udp_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context;
if (udp_chksum != IP_TRUE)
{
retval = IPCOM_ERR_BAD_PACKET;
goto next;
}
if (crc_bits != 0)
{
/* CRC validation of the re-constructed packet */
if (crc_bits == 8)
{
/* 8-bit CRC calculation */
calc_crc = iprohc_crc8(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
}
else if (crc_bits == 7)
{
/* 7-bit CRC calculation */
calc_crc = iprohc_crc7(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
}
else if (crc_bits == 3)
{
/* 3-bit CRC calculation */
calc_crc = iprohc_crc3(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
}
/* Compare the calculated CRC with the CRC carried in the packet */
if (calc_crc != crc)
retval = IPCOM_ERR_BAD_PACKET;
}
next:
/* Process mode transition */
IPROHC_D_MODE_TRANS(context, mode);
if (retval == IPCOM_SUCCESS)
{
/* The packet is successfully decompressed */
/* Increase the success counter */
context->num_decompressed ++;
/* State transits to Full Context: RFC 3095, 5.3.2.1 */
context->state = ROHC_DECOMP_STATE_FULL;
/* send ACK feedback for an IR/IR-DYN/type-2 packet */
if ((pkt_type == ROHC_PKT_IR) ||
(pkt_type == ROHC_PKT_IR_DYN) ||
(pkt_type == ROHC_PKT_TYPE_2))
{
if (context->trans == ROHC_DECOMP_TRANS_DONE)
/* Generate a FEEDBACK-1 feedback */
feedback = iprohc_create_feedback_1(context, backup_context->sn);
else
/* Generate a FEEDBACK-2 feedback */
feedback = iprohc_create_feedback_2(context, ROHC_FEEDBACK_ACK,
backup_context->sn);
}
/* Free the backup ip context */
iprohc_del_ip_context((void *)backup_context, IP_FALSE);
/* Free the backup udp context */
iprohc_del_udp_context((void *)backup_udp_context, IP_FALSE);
if ((feedback != IP_NULL) &&
(context->trans == ROHC_DECOMP_TRANS_INITIATED))
{
/* Feedback pkts that initiate the mode transition must */
/* carry CRC option */
iprohc_feedback_add_option(feedback, ROHC_FEEDBACK_OPT_CRC, 1, 0);
}
}
else
{
/* The packet decompression is failed */
/* Free the updated ip context */
iprohc_del_ip_context(((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context,
IP_FALSE);
/* Free the apdated udp context */
iprohc_del_udp_context(((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context,
IP_FALSE);
/* Restore the backuped previous context */
((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context = (void *)backup_context;
((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context = (void *)backup_udp_context;
/* Increase the failed counter */
context->num_failed ++;
IPROHC_D_F_STATE_TRANS(context, backup_context->sn);
}
return retval;
}
/*
*===========================================================================
* iprohc_fmt_udp_ip_ir
*===========================================================================
* Description: Format an UDP_IP profile IR packet.
*
* RFC 3095, 5.7.7.1, 5.11.1 Basic structure of the IR packet
*
* ---------------------------
* | Add-CID octet | if for small CIDs and CID != 0
* ---------------------------
* | 1 1 1 1 1 1 0 | D |
* ---------------------------
* | |
* / 0-2 octets of CID info / 1-2 octets if for large CIDs
* | |
* ---------------------------
* | Profile | 1 octet
* ---------------------------
* | CRC | 1 octet
* ---------------------------
* | |
* | Static chain | variable length
* | |
* ---------------------------
* | |
* | Dynamic chain | present if D = 1, variable length
* | |
* ---------------------------
* | Payload | variable length
* | |
* ---------------------------
*
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_fmt_udp_ip_ir(Iprohc_c_context *context, Ipcom_pkt *pkt)
{
Ip_err retval = IPCOM_SUCCESS;
Iprohc_c_ip_context *ip_context;
Iprohc_c_udp_context *udp_context;
int pointer;
Ip_u16 data;
Ip_bool has_dynamic = IP_FALSE;
Ip_u8 num_h, calc_crc;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_fmt_udp_ip_ir\n");
#endif
ip_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->ip_context;
udp_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->udp_context;
/* Init pointer to point to payload data */
pointer = udp_context->payload;
num_h = ip_context->ip_num;
/* 8-bit CRC calculation before compress/re-format the packet */
calc_crc = iprohc_crc8(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
/* Format SN, and save SN in WLSB structure */
pointer -= 2;
data = ip_htons(ip_context->sn);
ipcom_memcpy(&pkt->data[pointer], &data, 2);
#ifdef IPROHC_WLSB_LSB
iprohc_cmp_wlsb_add_val((cmp_wslb_cast *)&ip_context->sn_wlsb,
data, data);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_fmt_udp_ip_ir, wslb sn %d\n", data);
#endif /* ROHC_DEBUG */
#endif /* IPROHC_WLSB_LSB */
/* Format UDP dynamic chain */
IPROHC_FMT_UDP_DYNAMC(udp_context, pointer, has_dynamic, pkt);
/* Format IP dynamic chain */
IPROHC_FMT_IP_DYNAMC(ip_context, pointer, pkt, has_dynamic, num_h);
/* Format UDP static chain */
IPROHC_FMT_UDP_STATIC(udp_context, pointer, pkt);
/* Format IP static chain */
IPROHC_FMT_IP_STATIC(ip_context, pointer, pkt);
/* Format CRC */
pointer --;
pkt->data[pointer] = calc_crc;
/* Format profile ID */
pointer --;
pkt->data[pointer] = ROHC_PROFILE_UDP_IP;
/* Format large CID */
if (iprohc.large_cid)
{
Ip_u8 cid_size;
Ip_u16 cid = context->cid;
/*
* Encode large CID according to RFC 3095, section 4.5.6
* RFC 3095, section 5.2.2: If the first bit is 0, the CID uses
* one octet. If the first bit is 1, the CID uses two octets.
*/
if (context->cid < 128) /* 0 < cid < 128 (0x80) */
pointer --;
else /* 127 (0x7F) < cid < 16384 (0x4000) */
pointer -= 2;
IPROHC_ENCODE_LARGE_CID(pkt->data, pointer, cid, cid_size);
}
/* Format IR packet type: 1111110D, D=1 indicates dynamic chain exists */
pointer --;
if (has_dynamic)
pkt->data[pointer] = 0xFD;
/* Format small CID */
if (!iprohc.large_cid)
{
pointer --;
pkt->data[pointer] = 0xE0;
pkt->data[pointer] = (Ip_u8)(pkt->data[pointer] | ((Ip_u8)context->cid & 0x0F));
}
/* Move ipstart and start pointers in Ipcom_pkt */
pkt->ipstart = pkt->start = pointer;
return retval;
}
/*
*===========================================================================
* iprohc_fmt_udp_ip_irdyn
*===========================================================================
* Description: Format an UDP_IP profile IR-DYN packet.
*
* RFC 3095, 5.7.7.2, 5.11.1 Basic structure of the IR-DYN packet
*
* ---------------------------
* | Add-CID octet | if for small CIDs and CID != 0
* ---------------------------
* | 1 1 1 1 1 0 0 0 |
* ---------------------------
* | |
* / 0-2 octets of CID info / 1-2 octets if for large CIDs
* | |
* ---------------------------
* | Profile | 1 octet
* ---------------------------
* | CRC | 1 octet
* ---------------------------
* | |
* | Dynamic chain | variable length
* | |
* ---------------------------
* | |
* | Payload | variable length
* | |
* ---------------------------
*
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_fmt_udp_ip_irdyn(Iprohc_c_context *context, Ipcom_pkt *pkt)
{
Ip_err retval = IPCOM_SUCCESS;
Iprohc_c_ip_context *ip_context;
Iprohc_c_udp_context *udp_context;
int pointer;
Ip_u16 data;
Ip_bool has_dynamic = IP_FALSE;
Ip_u8 num_h, calc_crc;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_fmt_udp_ip_irdyn\n");
#endif
ip_context = ((Iprohc_c_udp_ip_context *)context->profile_context)->ip_context;
udp_context = ((Iprohc_c_udp_ip_context *)context->profile_context)->udp_context;
/* Init pointer to point to payload data */
pointer = udp_context->payload;
num_h = ip_context->ip_num;
/* 8-bit CRC calculation before compress/re-format the packet */
calc_crc = iprohc_crc8(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
/* Format SN, and save SN in WLSB structure */
pointer -= 2;
data = ip_htons(ip_context->sn);
ipcom_memcpy(&pkt->data[pointer], &data, 2);
#ifdef IPROHC_WLSB_LSB
iprohc_cmp_wlsb_add_val((cmp_wslb_cast *)&ip_context->sn_wlsb,
data, data);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_fmt_udp_ip_irdyn, wslb sn %d\n", data);
#endif /* ROHC_DEBUG */
#endif /* IPROHC_WLSB_LSB */
/* Format UDP dynamic chain */
IPROHC_FMT_UDP_DYNAMC(udp_context, pointer, has_dynamic, pkt);
/* Format IP dynamic chain */
IPROHC_FMT_IP_DYNAMC(ip_context, pointer, pkt, has_dynamic, num_h);
/* Format CRC */
pointer --;
pkt->data[pointer] = calc_crc;
/* Format profile ID */
pointer --;
pkt->data[pointer] = ROHC_PROFILE_UDP_IP;
/* Format large CID */
if (iprohc.large_cid)
{
Ip_u8 cid_size;
Ip_u16 cid = context->cid;
/*
* Encode large CID according to RFC 3095, section 4.5.6
* RFC 3095, section 5.2.2: If the first bit is 0, the CID uses
* one octet. If the first bit is 1, the CID uses two octets.
*/
if (context->cid < 128) /* 0 < cid < 128 (0x80) */
pointer --;
else /* 127 (0x7F) < cid < 16384 (0x4000) */
pointer -= 2;
IPROHC_ENCODE_LARGE_CID(pkt->data, pointer, cid, cid_size);
}
/* Format IR-DYN packet type: 11111000 */
pointer --;
pkt->data[pointer] = 0xF8;
/* Format small CID */
if (!iprohc.large_cid)
{
pointer --;
pkt->data[pointer] = 0xE0;
pkt->data[pointer] = (Ip_u8)(pkt->data[pointer] | ((Ip_u8)context->cid & 0x0F));
}
/* Move ipstart and start pointers in Ipcom_pkt */
pkt->ipstart = pkt->start = pointer;
return retval;
}
/*
*===========================================================================
* iprohc_fmt_udp_ip_general
*===========================================================================
* Description: Format an UDP_IP profile general compressed packet.
*
* RFC 3843, 3.6 General format for a compressed header
*
* ------------------------------
* | Add-CID octet | if for small CIDs and CID != 0
* ------------------------------
* | first octet of base header | (with type indication)
* ------------------------------
* | |
* / 0-2 octets of CID info / 1-2 octets if for large CIDs
* | |
* ------------------------------
* | remainder of base header | variable number of bits
* ------------------------------
* : :
* | Extension | extension, if X = 1 in base header
* : :
* ------------------------------
* : :
* | IP-ID of outer IPv4 header | 2 octets, if value (RND2) = 1
* : :
* ------------------------------
* / AH data for outer list / variable (not supported)
* ------------------------------
* : :
* | GRE checksum | 2 octets, if GRE flag C=1(not supported)
* : :
* ------------------------------
* : :
* | IP-ID of inner IPv4 header | 2 octets, if value (RND) = 1
* : :
* ------------------------------
* / AH data for inner list / variable (not supported)
* ------------------------------
* : :
* | GRE checksum | 2 octets, if GRE flag C=1(not supported)
* : :
* ------------------------------
* : :
* | UDP checksum | 2 octets if context(UDP Checksum) != 0
* : :
* ------------------------------
*
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_fmt_udp_ip_general(Iprohc_c_context *context, Ipcom_pkt *pkt)
{
Ip_err retval = IPCOM_SUCCESS;
Iprohc_ip_header *ip_header1, *ip_header2;
Iprohc_c_ip_context *ip_context;
Iprohc_c_udp_context * udp_context;
int pointer;
void *header1 = IP_NULL, *header2 = IP_NULL;
Ip_u8 base_header[2];
Ip_u8 crc = 0, size;
Ip_u32 sn_e;
Ip_bool has_dynamic = IP_FALSE;
#ifdef IPROHC_WLSB_LSB
Ip_u8 enc_val_ln;
#endif
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_fmt_udp_ip_general\n");
#endif
ip_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->ip_context;
udp_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->udp_context;
/* Init pointer to point to payload data */
pointer = udp_context->payload;
sn_e = ip_htons(ip_context->sn);
/* Calculate CRC before the packet is compressed/reformatted */
switch (context->pkt_type)
{
case ROHC_PKT_TYPE_0:
if (context->mode == ROHC_MODE_R)
{
/* Calculate 7-bit CRC */
crc = iprohc_crc7(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
}
else
{
/* Calculate 3-bit CRC */
crc = iprohc_crc3(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
}
break;
case ROHC_PKT_TYPE_1:
if (context->mode != ROHC_MODE_R)
{
/* Calculate 3-bit CRC */
crc = iprohc_crc3(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
}
break;
case ROHC_PKT_TYPE_2:
/* Calculate 7-bit CRC */
crc = iprohc_crc7(&pkt->data[pkt->ipstart],
udp_context->payload - pkt->ipstart);
break;
}
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_fmt_udp_ip_general, pkt_type %s, mode %s\n",
iprohc_pkt_type(context->pkt_type),
iprohc_context_mode(context->mode));
#endif
/* Init ROHC IP header1 (outer) and header2 (inner) */
ip_header1 = IPCOM_LIST_FIRST(&ip_context->ip_head);
if(ip_header1 == IP_NULL)
return IPCOM_ERR_INVALID_ARG;
ip_header2 = IPCOM_LIST_NEXT(&ip_header1->ip_list);
/* Init header1 */
if (ip_header1->packet_type == ROHC_PKT_IPV4)
{
#ifdef IPCOM_USE_INET
header1 = (void *)&(ip_header1->header.ip4);
#endif /* IPCOM_USE_INET */
}
else if (ip_header1->packet_type == ROHC_PKT_IPV6)
{
#ifdef IPCOM_USE_INET6
header1 = (void *)&(ip_header1->header.ip6);
#endif /* IPCOM_USE_INET6 */
}
if(header1 == IP_NULL)
return IPCOM_ERR_INVALID_ARG;
/* Init header 2 */
if (ip_header2 && ip_header2->packet_type == ROHC_PKT_IPV4)
{
#ifdef IPCOM_USE_INET
header2 = (void *)&(ip_header2->header.ip4);
#endif /* IPCOM_USE_INET */
}
else if (ip_header2 && ip_header2->packet_type == ROHC_PKT_IPV6)
{
#ifdef IPCOM_USE_INET6
header2 = (void *)&(ip_header2->header.ip6);
#endif /* IPCOM_USE_INET6 */
}
/* Add UDP checksum to the packet only if checksum is used */
if (udp_context->use_checksum == IP_TRUE)
IPROHC_FMT_UDP_DYNAMC(udp_context, pointer, has_dynamic, pkt);
/* Add dynamic chains for additional IP headers */
if (ip_context->ip_num > 2)
{
Ip_u8 num_h = (Ip_u8)(ip_context->ip_num - 2);
IPROHC_FMT_IP_DYNAMC(ip_context, pointer, pkt, has_dynamic, num_h);
}
#ifdef IPCOM_USE_INET
/* Add IP-ID of inner IPv4 header: ip_header2 */
if (ip_header2 && (ip_header2->packet_type == ROHC_PKT_IPV4) &&
ip_header2->rnd)
{
Ipcom_ip_header *ip4_header = &(ip_header2->header.ip4);
pointer -= 2;
ipcom_memcpy(&pkt->data[pointer], &ip4_header->id, 2);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_fmt_udp_ip_general, inner IP-ID: %x\n", ip4_header->id);
#endif
}
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET
/* Add IP-ID of outer IPv4 header: ip_header1 */
if (ip_header1 && (ip_header1->packet_type == ROHC_PKT_IPV4) &&
ip_header1->rnd)
{
Ipcom_ip_header *ip4_header = &(ip_header1->header.ip4);
pointer -= 2;
ipcom_memcpy(&pkt->data[pointer], &ip4_header->id, 2);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_fmt_udp_ip_general, outer IP-ID: %x\n", ip4_header->id);
#endif
}
#endif /* IPCOM_USE_INET */
/* Add extension */
/* RFC 3095, section 5.7.5, extension formats */
/* Inner IP header (ip2) correspond to the inner IP header if there */
/* are two, and the single IP header otherwise. */
/* Outer IP header (ip1) is always zero unless the context contains */
/* two IP headers. */
if (context->ext_type != ROHC_EXT_NO_EXT)
iprohc_fmt_extension(pkt,
&pointer,
context->ext_type,
header2?header1:IP_NULL,
header2?header2:header1,
ip_context->sn,
context->decline_mode_trans?ROHC_MODE_C:context->mode,
(Ip_u8)(ip_header2?ip_header1->header_flags:0),
(Ip_u8)(ip_header2?ip_header2->header_flags:ip_header1->header_flags));
#ifdef IPROHC_WLSB_LSB
/* Encode SN to 4 bits */
if (iprohc_cmp_wlsb_encode_val((cmp_wslb_cast *)&ip_context->sn_wlsb,
(Ip_u32)ip_htons(ip_context->sn), &sn_e, &enc_val_ln) != IP_TRUE)
{
IPCOM_LOG0(ERR,"iprohc_fmt_udp_ip_general, failed to encode SN");
IPROHC_ERROUT(IPCOM_ERR_FAILED);
}
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_fmt_udp_ip_general: encoded sn %u, context n_sn %u\n",
sn_e, ip_htons(ip_context->sn));
#endif
/* Save SN to WLSB structure */
iprohc_cmp_wlsb_add_val((cmp_wslb_cast *)&ip_context->sn_wlsb,
ip_htons(ip_context->sn), ip_htons(ip_context->sn));
#endif /* IPROHC_WLSB_LSB */
/* Format base header */
size = iprohc_fmt_base_header(base_header, context, header1,
(Ip_u8)sn_e, crc);
/* Add the second octet of of base header */
if (size == 2)
{
pointer --;
pkt->data[pointer] = base_header[1];
}
/* Add large CID */
if (iprohc.large_cid)
{
Ip_u8 cid_size;
Ip_u16 cid = context->cid;
/*
* Encode large CID according to RFC 3095, section 4.5.6
* RFC 3095, section 5.2.2: If the first bit is 0, the CID uses
* one octet. If the first bit is 1, the CID uses two octets.
*/
if (context->cid < 128) /* 0 < cid < 128 (0x80) */
pointer --;
else /* 127 (0x7F) < cid < 16384 (0x4000) */
pointer -= 2;
IPROHC_ENCODE_LARGE_CID(pkt->data, pointer, cid, cid_size);
}
/* Add the first octet of base header */
pointer --;
pkt->data[pointer] = base_header[0];
/* Format small CID */
if (!iprohc.large_cid)
{
pointer --;
pkt->data[pointer] = 0xE0;
pkt->data[pointer] = (Ip_u8)(pkt->data[pointer] | ((Ip_u8)context->cid & 0x0F));
}
/* Move ipstart and start pointers in Ipcom_pkt */
pkt->ipstart = pkt->start = pointer;
#ifdef IPROHC_WLSB_LSB
errout:
#endif /* IPROHC_WLSB_LSB */
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_fmt_udp_ip_general (end), retval %d\n", retval);
/*
iprohc_print_pkt(pkt);
*/
#endif
return retval;
}
/*
*===========================================================================
* iprohc_decomp_udp_ip_ir
*===========================================================================
* Description: Decompress an UDP_IP profile IR packet.
*
* Passed in packet is an IP profile IR Body packet, in format:
* RFC 3095, 5.7.7.1, 5.11.1 Basic structure of the IR packet
*
* ---------------------------
* | Profile | 1 octet
* ---------------------------
* | CRC | 1 octet
* ---------------------------
* | |
* | Static chain | variable length
* | |
* ---------------------------
* | |
* | Dynamic chain | present if D = 1, variable length
* | |
* ---------------------------
* | |
* | Payload | variable length
* | |
* ---------------------------
*
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_decomp_udp_ip_ir(Iprohc_d_context *context,
Ipcom_pkt *pkt, Ip_u8 type_data)
{
Ip_err retval = IPCOM_SUCCESS;
Iprohc_d_ip_context *ip_context, *backup_context;
Iprohc_d_udp_context *udp_context, *backup_udp_context;
Ip_u8 crc;
int pointer = pkt->ipstart, mode = -1;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_decomp_udp_ip_ir\n");
#endif
ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context;
udp_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context;
retval = iprohc_d_copy_ip_context(&backup_context, ip_context);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_ir, fail to make a copy of ip context");
return retval;
}
retval = iprohc_d_copy_udp_context(&backup_udp_context, udp_context);
if (retval != IPCOM_SUCCESS)
{
/* Free the backup ip context */
iprohc_del_ip_context((void *)backup_context, IP_FALSE);
IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_ir, fail to make a copy of udp context");
return retval;
}
if (!context->first_ir)
{
/* Update the context from the IR packet */
/* skip profile octet */
pointer++;
/* Record CRC */
crc = pkt->data[pointer];
pointer++;
/* Update the IP context from the static chain */
IPROHC_UPD_IP_STATIC(ip_context, pointer, pkt);
/* Update the UDP context from the static chain */
IPROHC_UPD_UDP_STATIC(udp_context, pointer, pkt);
/* if D bit is set, update the context from the Dynamic chain */
if (type_data & 0x01)
{
IPROHC_UPD_IP_DYNAMIC(ip_context, pointer, pkt);
IPROHC_UPD_UDP_DYNAMIC(udp_context, pointer, pkt);
}
/* Record SN in ip profile specific context, save in LSB structure */
ip_context->sn = ip_ntohs(*((Ip_u16 *)&(pkt->data[pointer])));
pointer += 2;
#ifdef IPROHC_WLSB_LSB
iprohc_dmp_lsb_save_last_valid_ref(&ip_context->sn_lsb,
ip_htons(ip_context->sn));
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_ir, (n)sn %d, lsb sn %d\n",
ip_htons(ip_context->sn), *((Ip_u16 *)&(pkt->data[pointer])));
#endif
/* Update ip_id offset from sn for every IPv4 header: ip_id - sn */
IPROHC_UPD_IPID_OFFSET(ip_context);
#endif /* IPROHC_WLSB_LSB */
/* Record UDP payload */
udp_context->payload = pointer;
}
else
{
/* Flip the flag for next IR packet */
context->first_ir = IP_FALSE;
crc = context->crc;
}
/* Move ipstart and start pointers to the UDP payload */
pkt->ipstart = pkt->start = udp_context->payload;
/* Get UDP header length */
IPROHC_GET_UDP_LENGTH(udp_context, pkt);
/* Re-construct the headers from the UDP context */
IPROHC_RECONSTRUCT_UDP(udp_context, pkt);
/* Move the IP payload and start to the beginning of the UDP header */
ip_context->payload_offset = pkt->start = pkt->ipstart; \
/* Re-construct the headers from the context */
IPROHC_RECONSTRUCT_IP(ip_context, pkt);
retval = iprohc_d_udp_ip_crc_validate(context, backup_context, backup_udp_context,
pkt, ROHC_PKT_IR, crc, 8, mode, IP_TRUE);
return retval;
}
/*
*===========================================================================
* iprohc_decomp_udp_ip_irdyn
*===========================================================================
* Description: Decompress an UDP_IP profile IR-DYN packet.
*
* Passed in packet is an IP profile IR-DYN Body packet, in format:
* RFC 3095, 5.7.7.2, 5.11.1 Basic structure of the IR-DYN packet
*
* ---------------------------
* | Profile | 1 octet
* ---------------------------
* | CRC | 1 octet
* ---------------------------
* | |
* | Dynamic chain | variable length
* | |
* ---------------------------
* | |
* | Payload | variable length
* | |
* ---------------------------
*
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_decomp_udp_ip_irdyn(Iprohc_d_context *context,
Ipcom_pkt *pkt, Ip_u8 type_data)
{
Ip_err retval = IPCOM_SUCCESS;
Iprohc_d_ip_context *ip_context, *backup_context;
Iprohc_d_udp_context *udp_context, *backup_udp_context;
Ip_u8 crc;
int pointer = pkt->ipstart, mode = -1;
IPCOM_UNUSED_ARG(type_data);
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_decomp_udp_ip_irdyn\n");
#endif
ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context;
udp_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context;
retval = iprohc_d_copy_ip_context(&backup_context, ip_context);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_irdyn, fail to make a copy of ip context");
return retval;
}
retval = iprohc_d_copy_udp_context(&backup_udp_context, udp_context);
if (retval != IPCOM_SUCCESS)
{
/* Free the backup ip context */
iprohc_del_ip_context((void *)backup_context, IP_FALSE);
IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_irdyn, fail to make a copy of udp context");
return retval;
}
/* Update the context from the IR packet */
/* skip profile octet */
pointer++;
/* Record CRC */
crc = pkt->data[pointer];
pointer++;
/* Update the context from the Dynamic chain */
IPROHC_UPD_IP_DYNAMIC(ip_context, pointer, pkt);
IPROHC_UPD_UDP_DYNAMIC(udp_context, pointer, pkt);
/* Record SN in ip profile specific context, save SN in LSB structure */
ip_context->sn = ip_ntohs(*((Ip_u16 *)&(pkt->data[pointer])));
pointer += 2;
#ifdef IPROHC_WLSB_LSB
iprohc_dmp_lsb_save_last_valid_ref(&ip_context->sn_lsb,
ip_htons(ip_context->sn));
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_irdyn, lsb sn %d\n",
ip_htons(ip_context->sn));
#endif
/* Update ip_id offset from sn for every IPv4 header: ip_id - sn */
IPROHC_UPD_IPID_OFFSET(ip_context);
#endif /* IPROHC_WLSB_LSB */
/* Record the UDP payload. Move ipstart and start pointers to the UDP payload */
pkt->ipstart = pkt->start = udp_context->payload = pointer;
/* Get UDP header length */
IPROHC_GET_UDP_LENGTH(udp_context, pkt);
/* Re-construct the headers from the UDP context */
IPROHC_RECONSTRUCT_UDP(udp_context, pkt);
/* Move start pointer to the UDP header. Record the IP payload.*/
ip_context->payload_offset = pkt->start = pkt->ipstart; \
/* Re-construct the headers from the context */
IPROHC_RECONSTRUCT_IP(ip_context, pkt);
retval = iprohc_d_udp_ip_crc_validate(context, backup_context, backup_udp_context,
pkt, ROHC_PKT_IR_DYN, crc, 8, mode, IP_TRUE);
return retval;
}
/*
*===========================================================================
* iprohc_decomp_udp_ip_general
*===========================================================================
* Description: Decompress an UDP_IP profile general packet.
*
* Passed in packet is an IP profile type0/type1/type2 Body packet, in format:
* RFC 3843, 3.6 General format for a compressed header
*
* ------------------------------
* | remainder of base header | variable number of bits
* ------------------------------
* : :
* | Extension | extension, if X = 1 in base header
* : :
* ------------------------------
* : :
* | IP-ID of outer IPv4 header | 2 octets, if value (RND2) = 1
* : :
* ------------------------------
* / AH data for outer list / variable (not supported)
* ------------------------------
* : :
* | GRE checksum | 2 octets, if GRE flag C=1(not supported)
* : :
* ------------------------------
* : :
* | IP-ID of inner IPv4 header | 2 octets, if value (RND) = 1
* : :
* ------------------------------
* / AH data for inner list / variable (not supported)
* ------------------------------
* : :
* | GRE checksum | 2 octets, if GRE flag C=1(not supported)
* : :
* ------------------------------
* : :
* | UDP checksum | 2 octets if context(UDP Checksum) != 0
* : :
* ------------------------------
*
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_decomp_udp_ip_general(Iprohc_d_context *context,
Ipcom_pkt *pkt, Ip_u8 pkt_type, Ip_u8 type_data)
{
Ip_err retval = IPCOM_SUCCESS;
Iprohc_d_ip_context *ip_context, *backup_context;
Iprohc_d_udp_context *udp_context, *backup_udp_context;
int pointer = pkt->ipstart;
Ip_u8 sn, data, crc = 0, crc_bits = 0;
int mode = -1;
Ip_u32 sn_d = 0;
int in_nbo = -1, in_rnd = -1, out_nbo = -1, out_rnd = -1;
Iprohc_ip_header *in_header, *out_header;
Ip_bool udp_chksum = IP_TRUE;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_decomp_udp_ip_general, pkt type %s\n",
iprohc_pkt_type(pkt_type));
#endif
ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context;
udp_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context;
out_header = IPCOM_LIST_FIRST(&ip_context->ip_head);
if(out_header == IP_NULL)
return IPCOM_ERR_INVALID_ARG;
in_header = IPCOM_LIST_NEXT(&out_header->ip_list);
retval = iprohc_d_copy_ip_context(&backup_context, ip_context);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_general, fail to make a copy of ip context");
return retval;
}
retval = iprohc_d_copy_udp_context(&backup_udp_context, udp_context);
if (retval != IPCOM_SUCCESS)
{
/* Free the backup ip context */
iprohc_del_ip_context((void *)backup_context, IP_FALSE);
IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_general, fail to make a copy of udp context");
return retval;
}
switch (pkt_type)
{
case ROHC_PKT_TYPE_0:
if (context->mode == ROHC_MODE_R)
{
/* It is in R-0-CRC format */
/* Get second octet of base header: SN(LSB) + CRC */
data = pkt->data[pointer];
/* Record CRC */
crc = (Ip_u8)(data & 0x7F);
crc_bits = 7;
/* Get sn (7 bits) */
sn_d = (Ip_u32)((type_data & 0x3F) << 1) + (Ip_u32)((data & 0x80) >> 7);
sn = (Ip_u8)sn_d;
#ifdef IPROHC_WLSB_LSB
/* Decode and save SN */
iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d,
&ip_context->sn_lsb, (Ip_u32)sn, 7);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general(type 0/R): header sn %d, sn_d %d\n",
sn, sn_d);
#endif
#endif /* IPROHC_WLSB_LSB */
/* Move pointer */
pointer ++;
}
else
{
/* It is in UO-0 format */
/* Record CRC */
crc = (Ip_u8)(type_data & 0x07);
crc_bits = 3;
/* Get sn (4 bits) */
sn_d = (Ip_u32)(type_data & 0x78) >> 3;
sn = (Ip_u8)sn_d;
#ifdef IPROHC_WLSB_LSB
/* Decode and save SN */
iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d,
&ip_context->sn_lsb, (Ip_u32)sn, 4);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general(type 0/UO): header sn %d, sn_d %d\n",
sn, sn_d);
#endif
#endif /* IPROHC_WLSB_LSB */
}
break;
case ROHC_PKT_TYPE_1:
/* Get second octet of base header: X + CRC */
data = pkt->data[pointer];
pointer ++;
if (context->mode == ROHC_MODE_R)
{
/* It is in R-1 format */
/* Get sn: 6 bits */
sn_d = type_data & 0x3F;
sn = (Ip_u8)sn_d;
#ifdef IPROHC_WLSB_LSB
/* Decode SN */
iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d,
&ip_context->sn_lsb, (Ip_u32)sn, 6);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general(type 1/R): header sn %d, sn_d %d\n",
sn, sn_d);
#endif
#endif /* IPROHC_WLSB_LSB */
if (data & 0x80)
{
/* may update ip-id in the extension parsing funtion */
iprohc_parse_extension(in_header?&(out_header->header):IP_NULL,
in_header?&(in_header->header):&(out_header->header),
&sn, &mode,
&in_nbo, &in_rnd,
&out_nbo, &out_rnd,
pkt, &pointer);
}
}
else
{
/* It is in UO-1 format */
/* Record CRC */
crc = (Ip_u8)(data & 0x07);
crc_bits = 3;
/* Get sn: 5 bits */
sn_d = (data & 0xF8) >> 3;
sn = (Ip_u8)sn_d;
#ifdef IPROHC_WLSB_LSB
/* Decode and save SN */
iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d,
&ip_context->sn_lsb, (Ip_u32)sn, 5);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general(type 1/UO): header sn %d, sn_d %d\n",
sn, sn_d);
#endif
#endif /* IPROHC_WLSB_LSB */
}
break;
case ROHC_PKT_TYPE_2:
/* Get sn: 5 bits */
sn_d = (type_data & 0x1F);
sn = (Ip_u8)sn_d;
#ifdef IPROHC_WLSB_LSB
/* Decode and save SN */
iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d,
&ip_context->sn_lsb, (Ip_u32)sn, 5);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general(type 2): header sn %d, sn_d %d\n",
sn, sn_d);
#endif
#endif /* IPROHC_WLSB_LSB */
/* Get second octet of base header: X + CRC */
data = pkt->data[pointer];
/* Record CRC and move pointer */
crc = (Ip_u8)(data & 0x7F);
crc_bits = 7;
pointer ++;
if (data & 0x80)
iprohc_parse_extension(in_header?&(out_header->header):IP_NULL,
in_header?&(in_header->header):&(out_header->header),
&sn, &mode,
&in_nbo, &in_rnd,
&out_nbo, &out_rnd,
pkt, &pointer);
break;
}
#ifdef IPCOM_USE_INET
/* Update in/out BNO/RND */
if (in_nbo != -1)
{
if (in_header)
in_header->nbo = in_nbo;
else
out_header->nbo = in_nbo;
}
if (in_rnd != -1)
{
if (in_header)
in_header->rnd = in_rnd;
else
out_header->rnd = in_rnd;
}
if (out_nbo != -1) out_header->nbo = out_nbo;
if (out_rnd != -1) out_header->rnd = out_rnd;
#endif /* #ifdef IPCOM_USE_INET */
/* Update SN */
ip_context->sn = ip_ntohs(sn_d);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general: context (n)sn %d\n",
ip_htons(ip_context->sn));
#endif
/* Check for IP-ID of outer IPv4 header */
if (out_header->packet_type == ROHC_PKT_IPV4)
{
#ifdef IPCOM_USE_INET
if (out_header->rnd)
{
/* Get IP-ID of outer IPv4 header */
ipcom_memcpy(&(out_header->header.ip4.id),
&(pkt->data[pointer]), 2);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general: outer IP-ID(ramdon) %x\n",
out_header->header.ip4.id);
#endif
pointer += 2;
}
else
{
/* Calcuate IP-ID from SN */
out_header->header.ip4.id = (Ip_u16)(out_header->offset +
ip_htons(ip_context->sn));
}
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general: outer IP-ID %x\n",
out_header->header.ip4.id);
#endif
#endif /* #ifdef IPCOM_USE_INET */
}
if (in_header && in_header->packet_type == ROHC_PKT_IPV4)
{
#ifdef IPCOM_USE_INET
if (in_header->rnd)
{
/* Get IP-ID of inner IPv4 header */
ipcom_memcpy(&(in_header->header.ip4.id),
&(pkt->data[pointer]), 2);
pointer += 2;
}
else
{
/* Calcuate IP-ID from SN */
in_header->header.ip4.id = (Ip_u16)(in_header->offset +
ip_htons(ip_context->sn));
}
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_decomp_udp_ip_general: inner IP-ID %x\n",
in_header->header.ip4.id);
#endif
#endif /* #ifdef IPCOM_USE_INET */
}
/* Parse the list of dynamic chains for additional IP headers */
if (ip_context->ip_num > 2)
IPROHC_UPD_IP_ADDTIONAL_DYNAMIC(ip_context, pointer, pkt);
/* Get the UDP dynamic chain and validate udp checksum usage in a genral packet.
The checksum is not sent if it is not used */
IPROHC_UPD_UDP_DYNAMIC1(udp_context, pointer, pkt, udp_chksum);
/* Record the UDP payload. Move ipstart and start pointers to the UDP payload */
pkt->ipstart = pkt->start = udp_context->payload = pointer;
/* Calculate the UDP header length */
IPROHC_GET_UDP_LENGTH(udp_context, pkt);
/* Re-construct the headers from the UDP context */
IPROHC_RECONSTRUCT_UDP(udp_context, pkt);
/* Move start pointer to the UDP header. Record the IP payload.*/
ip_context->payload_offset = pkt->start = pkt->ipstart; \
/* Re-construct the headers from the context */
IPROHC_RECONSTRUCT_IP(ip_context, pkt);
retval = iprohc_d_udp_ip_crc_validate(context, backup_context, backup_udp_context,
pkt, pkt_type, crc, crc_bits, mode, udp_chksum);
return retval;
}
/*
*===========================================================================
* iprohc_udp_c_get_header
*===========================================================================
* Description: Get UDP header from the packet on the compressor.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err iprohc_udp_c_get_header(Ipcom_pkt *pkt, udp_header *header)
{
Ip_err retval = IPCOM_SUCCESS;
ipcom_memset(header, 0, sizeof(udp_header));
ipcom_memcpy(header, &pkt->data[pkt->tlstart], sizeof(udp_header));
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_c_get_header, udp src port %u, dst port %u, pkt length %u, \
checksum %u, pkt tlstart %d\n",
ipcom_ntohs(header->src_port),
ipcom_ntohs(header->dst_port),
ipcom_ntohs(header->length),
ipcom_ntohs(header->checksum), pkt->tlstart);
#endif
return retval;
}
/*
*===========================================================================
* iprohc_udp_c_init
*===========================================================================
* Description: Initialize UDP compressor context.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err iprohc_udp_c_init(Iprohc_c_udp_context *udp_context)
{
Ip_err retval = IPCOM_SUCCESS;
udp_context->use_checksum = IP_TRUE;
/* Init UDP statistic information */
udp_context->udp_pkt_count = 0;
return retval;
}
/*
*===========================================================================
* iprohc_udp_d_init
*===========================================================================
* Description: Initialize UDP decompressor context.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err iprohc_udp_d_init(Iprohc_d_udp_context *udp_context)
{
Ip_err retval = IPCOM_SUCCESS;
udp_context->use_checksum = IP_TRUE;
/* Init UDP statistic information */
udp_context->udp_pkt_count = 0;
return retval;
}
/*
*===========================================================================
* iprohc_del_udp_context
*===========================================================================
* Description: Delete a udp profile specific compression/decompression
* context.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
iprohc_del_udp_context(void *context, Ip_bool is_comp)
{
Ip_err retval = IPCOM_SUCCESS;
IPCOM_UNUSED_ARG(is_comp);
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_del_udp_context\n");
#endif
ipcom_free(context);
context = IP_NULL;
return retval;
}
/*
****************************************************************************
* PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* iprohc_profile_udp_ip_register
*===========================================================================
* Description: Register ROHC UDP_IP profile (0x0002)
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
iprohc_profile_udp_ip_register(void)
{
Iprohc_profile *profile;
#ifdef ROHC_DEBUG
ipcom_printf("Calling iprohc_profile_udp_ip_register\n");
#endif
IPROHC_LOCK();
if (iprohc.profiles[ROHC_PROFILE_UDP_IP].configured)
{
IPCOM_LOG0(ERR, "iprohc_profile_udp_ip_register, profile already configured\n");
IPROHC_UNLOCK();
return IPCOM_ERR_ALREADY_INSTALLED;
}
profile = &(iprohc.profiles[ROHC_PROFILE_UDP_IP]);
/* Register the UDP_IP profile specific functions */
profile->p_deregister = iprohc_udp_ip_deregister;
profile->c_find_context = iprohc_udp_ip_c_find_context;
profile->c_create_context = iprohc_udp_ip_c_create_context;
profile->c_del_context = iprohc_udp_ip_c_del_context;
profile->c_print_context = iprohc_udp_ip_c_print_context;
profile->c_process_feedback = iprohc_udp_ip_c_process_feedback;
profile->c_compress = iprohc_udp_ip_c_compress;
profile->d_find_context = iprohc_udp_ip_d_find_context;
profile->d_create_context = iprohc_udp_ip_d_create_context;
profile->d_del_context = iprohc_udp_ip_d_del_context;
profile->d_print_context = iprohc_udp_ip_d_print_context;
profile->d_decompress = iprohc_udp_ip_d_decompress;
/* Increment the profile counter and set configured flag */
iprohc.profile_num++;
profile->configured = IP_TRUE;
IPROHC_UNLOCK();
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_profile_udp_ip_register, registered\n");
#endif
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* iprohc_udp_ip_deregister
*===========================================================================
* Description: De-register ROHC UDP_IP profile (0x0002)
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
iprohc_udp_ip_deregister(void)
{
Iprohc_profile *profile;
#ifdef ROHC_DEBUG
ipcom_printf("Calling iprohc_udp_ip_deregister\n");
#endif
IPROHC_LOCK();
if (iprohc.profiles[ROHC_PROFILE_UDP_IP].configured == IP_FALSE)
{
IPCOM_LOG0(ERR, "iprohc_udp_ip_deregister, profile not configured\n");
IPROHC_UNLOCK();
return IPCOM_ERR_NOT_INSTALLED;
}
profile = &(iprohc.profiles[ROHC_PROFILE_UDP_IP]);
/* NULL all the IP profile specific functions */
profile->p_deregister = IP_NULL;
profile->c_find_context = IP_NULL;
profile->c_create_context = IP_NULL;
profile->c_del_context = IP_NULL;
profile->c_print_context = IP_NULL;
profile->c_process_feedback = IP_NULL;
profile->c_compress = IP_NULL;
profile->d_find_context = IP_NULL;
profile->d_create_context = IP_NULL;
profile->d_del_context = IP_NULL;
profile->d_print_context = IP_NULL;
profile->d_decompress = IP_NULL;
/* Decrement the profile counter and clear configured flag */
iprohc.profile_num--;
profile->configured = IP_FALSE;
IPROHC_UNLOCK();
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_deregister, deregistered\n");
#endif
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* iprohc_udp_ip_c_find_context
*===========================================================================
* Description: Find a compression context matching the packet. The
* comparison is based on src/dst IP addresses in each IP
* header and UDP ports. If found a compression context, it also updates
* to-be-transmitted packet info in a compression context.
* Updated fields include state, pkt_type, ext_type in the
* compression context, add_dynamic_chain in IP profile
* compression context, rnd, nbo, and header_flags in
* each ROHC IP header and UDP context fields.
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
iprohc_udp_ip_c_find_context(Iprohc_compressor *comp, Ipcom_pkt *pkt,
Iprohc_c_context **context)
{
Iprohc_c_context *c_context;
Iprohc_ip_header *ip_header, *n_ip_header = IP_NULL;
int pointer = pkt->ipstart;
Ip_err retval = IPCOM_SUCCESS;
udp_header udp_header_;
void* profile_context;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_udp_ip_c_find_context\n");
#endif
/* Get UDP heder from the packet */
(void)iprohc_udp_c_get_header(pkt, &udp_header_);
IPROHC_COMP_LOCK(comp);
for (c_context = IPCOM_LIST_FIRST(&comp->context_head); c_context != IP_NULL;
c_context = IPCOM_LIST_NEXT(&c_context->context_list))
{
Iprohc_c_ip_context *ip_context;
Iprohc_c_udp_context *udp_context;
int num_ip;
if (c_context->profileid != ROHC_PROFILE_UDP_IP) continue;
IPROHC_C_CONTEXT_LOCK(c_context);
pointer = pkt->ipstart;
ip_context = ((Iprohc_c_udp_ip_context *) c_context->profile_context)->ip_context;
udp_context = ((Iprohc_c_udp_ip_context *) c_context->profile_context)->udp_context;
if((((Iprohc_c_udp_ip_context *) c_context->profile_context)->udp_context->src_port !=
udp_header_.src_port) ||
(((Iprohc_c_udp_ip_context *) c_context->profile_context)->udp_context->dst_port !=
udp_header_.dst_port)) continue;
/* Compare src and dst IP addresses in headers */
for (ip_header = IPCOM_LIST_FIRST(&ip_context->ip_head), num_ip = 1;
ip_header && (pointer != -1);
ip_header = n_ip_header, num_ip++)
{
n_ip_header = IPCOM_LIST_NEXT(&ip_header->ip_list);
if (ip_header->packet_type != (pkt->data[pointer]>>4))
break;
#ifdef IPCOM_USE_INET
if (ip_header->packet_type == ROHC_PKT_IPV4)
{
Ipcom_ip_header *ip4;
ip4 = (Ipcom_ip_header *)&pkt->data[pointer];
#ifdef ROHC_DEBUG
{
char buf[48];
(void)ipcom_inet_ntop(IP_AF_INET, &ip4->src.addr32, buf, sizeof(buf));
ipcom_printf("iprohc_udp_ip_c_find_context: IPv4 src addr %s\n", buf);
(void)ipcom_inet_ntop(IP_AF_INET, &ip4->dst.addr32, buf, sizeof(buf));
ipcom_printf("iprohc_udp_ip_c_find_context: IPv4 dst addr %s\n", buf);
}
#endif
/* Enforce IPv4 header fields according to RFC 3095, 5.7.7.4 */
/* IHL must be 5, MF flag must be 0, Fragment offset must be 0 */
/* Don't compress packet less than 64(??) bytes long on an */
/* ethernet interface. */
if (((ip4->vers_len & 0x0F) != 5) ||
IPCOM_ISFRAG(ip4->frag) ||
((num_ip == 1) &&
(((Iprohc_interface *)(comp->interface))->netif->type
== IP_IFT_ETHER) &&
(ip_ntohs(ip4->length) < 64)))
{
IPCOM_LOG0(ERR,"iprohc_udp_ip_c_find_context, IPv4 header fileds");
IPROHC_C_CONTEXT_UNLOCK(c_context);
c_context = IP_NULL;
IPROHC_LEAVE(IPCOM_ERR_IGNORED_PACKET);
}
/* Compare src and dst IPv4 address */
if ((ip4->src.addr32 != ip_header->header.ip4.src.addr32) ||
(ip4->dst.addr32 != ip_header->header.ip4.dst.addr32))
break;
/* Check the protocl field */
if ((ip4->protocol == IP_IPPROTO_IPIP) ||
(ip4->protocol == IP_IPPROTO_IPV6))
{
/* Next header is IPinIP or IPv6, move pinter */
pointer += 4 * (pkt->data[pointer] & 0x0F);
}
else
/* The end of IP header, exit for loop */
pointer = -1;
}
#ifdef IPCOM_USE_INET6
else
#endif
#endif /* #ifdef IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
if (ip_header->packet_type == ROHC_PKT_IPV6)
{
Ipcom_ip6_header *ip6;
ip6 = (Ipcom_ip6_header *)&pkt->data[pointer];
/* Don't compress a packet whose payload is less than 50(??) */
/* bytes long on an ethernet interface. */
if ((num_ip == 1) &&
(((Iprohc_interface *)(comp->interface))->netif->type
== IP_IFT_ETHER) &&
(ip_ntohs(ip6->plen) < 50))
{
IPCOM_LOG0(ERR,"iprohc_udp_ip_c_find_context, IPv6 header fileds");
IPROHC_C_CONTEXT_UNLOCK(c_context);
c_context = IP_NULL;
IPROHC_LEAVE(IPCOM_ERR_IGNORED_PACKET);
}
/* Compare src and dst IPv6 address */
if ((ipcom_memcmp(&ip6->src, &ip_header->header.ip6.src,
sizeof(struct Ip_in6_addr)) != 0) ||
(ipcom_memcmp(&ip6->dst, &ip_header->header.ip6.dst,
sizeof(struct Ip_in6_addr)) != 0))
break;
/* Check the protocl field */
if (ip6->nxt == IP_IPPROTO_IPV6)
{
/* Next header is IPv6, move pinter */
pointer += IPROHC_IP6_HDR_SIZE;
}
else
/* The end of IP header, exit for loop */
pointer = -1;
}
#endif /* #ifdef IPCOM_USE_INET6 */
}
if ((n_ip_header == IP_NULL) && (pointer == -1))
/* address match until the end of header chain ... find the context */
{
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_c_find_context, found the context\n");
/*
iprohc_c_print_a_context(c_context);
*/
#endif /* ROHC_DEBUG */
/* Update the UDP context and decide UDP state */
IPROHC_UDP_UPDATE_CONTEXT(c_context, udp_context, udp_header_, pkt);
/* Increase SN number */
ip_context->sn = ip_ntohs(ip_htons(ip_context->sn) + 1);
/* Update Ip context */
if ((c_context->state == ROHC_COMP_STATE_IR) &&
(c_context->num_ir < IPROHC_MAX_IRS))
{
/* Continue with IR packet type and no extension. */
/* Record new IP headers, and re-calculate the RND and */
/* NBO flags in Iprohc_ip_header */
iprohc_c_update_ip_hdrs(ip_context, pkt);
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_c_find_context, update IP headers\n");
/*
iprohc_c_print_a_context(c_context);
*/
#endif /* ROHC_DEBUG */
}
else
{
/* update ip context info. */
profile_context = c_context->profile_context;
c_context->profile_context = (void*) ip_context;
iprohc_c_update_ip_context(c_context, pkt);
c_context->profile_context = profile_context;
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_c_find_context, update context info\n");
/*
iprohc_c_print_a_context(c_context);
*/
#endif /* ROHC_DEBUG */
}
IPROHC_C_CONTEXT_UNLOCK(c_context);
break;
}
IPROHC_C_CONTEXT_UNLOCK(c_context);
}
leave:
IPROHC_COMP_UNLOCK(comp);
*context = c_context;
return retval;
}
/*
*===========================================================================
* iprohc_udp_ip_c_create_context
*===========================================================================
* Description: Create a compression context for the packet.
* The function will check on UDP and IP header fields
* If headers don't conform to the rules, it won't create
* a compression context and the packet will be returned
* without compression.
* Parameters:
* Returns:
*
*/
IP_PUBLIC Iprohc_c_context *
iprohc_udp_ip_c_create_context(Iprohc_compressor *comp,
Ipcom_pkt *pkt)
{
Iprohc_c_context *c_context = IP_NULL;
Iprohc_c_ip_context *ip_context;
Iprohc_c_udp_context *udp_context;
Iprohc_c_udp_ip_context *udp_ip_context;
udp_header udp_header_;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_udp_ip_c_create_context\n");
#endif
/* Create profile specific context structure */
udp_ip_context = ipcom_malloc(sizeof(Iprohc_c_udp_ip_context));
if (udp_ip_context == IP_NULL)
{
IPCOM_LOG0(ERR,"iprohc_udp_ip_c_create_context, out of memory(p context)");
return c_context = IP_NULL;
}
ipcom_memset(udp_ip_context, 0, sizeof(Iprohc_c_udp_ip_context));
/* Create udp profile specific context structure */
udp_context = ipcom_malloc(sizeof(Iprohc_c_udp_context));
if (udp_context == IP_NULL)
{
ipcom_free(udp_ip_context);
IPCOM_LOG0(ERR,"iprohc_udp_ip_c_create_context, out of memory(p context)");
return c_context = IP_NULL;
}
ipcom_memset(udp_context, 0, sizeof(Iprohc_c_udp_context));
IPROHC_COMP_LOCK(comp);
c_context = iprohc_ip_c_create_context(comp, pkt);
if (c_context == IP_NULL)
{
ipcom_free(udp_ip_context);
ipcom_free(udp_context);
goto errout;
}
IPROHC_C_CONTEXT_LOCK(c_context);
c_context->profileid = ROHC_PROFILE_UDP_IP;
/* iprohc_ip_c_create_context creates ip_context. c_context->profile_context
contains the pointer to the ip_context */
ip_context = (Iprohc_c_ip_context*) c_context->profile_context;
c_context->profile_context = udp_ip_context;
((Iprohc_c_udp_ip_context *) c_context->profile_context)->udp_context = udp_context;
((Iprohc_c_udp_ip_context *) c_context->profile_context)->ip_context = ip_context;
(void)iprohc_udp_c_get_header(pkt, &udp_header_);
iprohc_udp_c_init(udp_context);
IPROHC_UDP_INIT_CONTEXT(udp_context, udp_header_, pkt);
/* This should never happen. This can be caused for example if IP code
does not process all extension headers up to the UDP header */
if(ip_context->payload_offset != (udp_context->payload - 8))
{
iprohc_del_udp_ip_context(c_context->profile_context, IP_TRUE);
ipcom_free(c_context->profile_context);
comp->context_num--;
/* Recover CID */
comp->to_be_used_cid--;
comp->cid_bit_map[c_context->cid >> 4] = (Ip_u16)(comp->cid_bit_map[c_context->cid >> 4] &
~(1 << (c_context->cid & 0x0f)));
ipcom_list_remove(&c_context->context_list);
IPROHC_C_CONTEXT_UNLOCK(c_context);
iprohc_c_context_common_del(c_context);
IPCOM_LOG0(ERR,"iprohc_udp_ip_c_create_context, payload mismatch");
goto errout;
}
IPROHC_C_CONTEXT_UNLOCK(c_context);
goto leave;
errout:
c_context = IP_NULL;
leave:
IPROHC_COMP_UNLOCK(comp);
return c_context;
}
/*
*===========================================================================
* iprohc_udp_ip_c_del_context
*===========================================================================
* Description: Delete a compression context.
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
iprohc_udp_ip_c_del_context(Iprohc_c_context *context)
{
Ip_err retval = IPCOM_SUCCESS;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_udp_ip_c_del_context\n");
#endif
if (context == IP_NULL)
return retval;
IPROHC_C_CONTEXT_LOCK(context);
/* Remove the context from the compressor */
ipcom_list_remove(&context->context_list);
/* free profile specific context structure */
if (context->profile_context)
{
iprohc_del_udp_ip_context(context->profile_context, IP_TRUE);
ipcom_free(context->profile_context);
}
IPROHC_C_CONTEXT_UNLOCK(context);
/* free context structure */
iprohc_c_context_common_del(context);
return retval;
}
/*
*===========================================================================
* iprohc_udp_ip_c_print_context
*===========================================================================
* Description: Debug: print a compression context.
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
iprohc_udp_ip_c_print_context(Iprohc_c_context *context)
{
Iprohc_c_ip_context *ip_context;
Iprohc_c_udp_context *udp_context;
ip_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->ip_context;
udp_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->udp_context;
ipcom_printf(" sn (network order): %d, sn: %d\n",
ip_htons(ip_context->sn), ip_context->sn);
ipcom_printf(" add_dynamic_chain: %s\n",
ip_context->add_dynamic_chain?"Yes":"No");
ipcom_printf(" ip_num: %d\n", ip_context->ip_num);
ipcom_printf(" payload_offset: %d\n",
udp_context->payload);
ipcom_printf(" udp src_port: %u\n",
ip_ntohs(udp_context->src_port));
ipcom_printf(" udp dst_port: %u\n",
ip_ntohs(udp_context->dst_port));
ipcom_printf(" udp pkt length: %u\n",
ip_ntohs(udp_context->length));
ipcom_printf(" udp checksum: %u\n",
ip_ntohs(udp_context->checksum));
ipcom_printf(" udp checksum is used: %s\n",
udp_context->use_checksum?"Yes":"No");
}
/*
*===========================================================================
* iprohc_udp_ip_c_process_feedback
*===========================================================================
* Description: Process a received feedback data.
*
* The feedback data has the following structure:
*
* ---------------------------
* : Add-CID octet : if for small CIDs and (CID != 0)
* ---------------------------
* : :
* / large CID / 1 - 2 octects for large CIDs
* : (4.5.6 encoding) :
* ---------------------------
* / feedback field / *
* The feedback field can have either of the following two formats:
*
* FEEDBACK-1
*
* ----------------------------
* | profile specific info | 1 octet
* ----------------------------
*
* FEEDBACK-2
*
* ----------------------------
* |Acktype| |
* --------- profile specific / at least 2 octets
* / info |
* ----------------------------
*
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
iprohc_udp_ip_c_process_feedback(Iprohc_c_context *context, Ip_u8 *feedback,
Ip_u8 size)
{
return iprohc_ip_c_process_feedback(context, feedback, size);
}
/*
*===========================================================================
* iprohc_udp_ip_c_compress
*===========================================================================
* Description: Compress a packet.
* The passed-in parameter pkt is a normal uncompressed packet.
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
iprohc_udp_ip_c_compress(Iprohc_c_context *context, Ipcom_pkt *pkt)
{
Ip_err retval = IPCOM_SUCCESS;
Iprohc_c_ip_context *ip_context;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_udp_ip_c_compress, context %x, pkt type %s\n",
context, iprohc_pkt_type(context->pkt_type));
ipcom_printf("iprohc_udp_ip_c_compress, ext type %d, %s\n",
context->ext_type, iprohc_ext_type(context->ext_type));
#endif
IPROHC_C_CONTEXT_LOCK(context);
ip_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->ip_context;
switch (context->pkt_type)
{
case ROHC_PKT_IR:
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_c_compress, format an IR packet\n");
#endif
retval = iprohc_fmt_udp_ip_ir(context, pkt);
if (retval == IPCOM_SUCCESS)
{
/* Increase IR packet counter */
context->num_ir ++;
/* Reset retx_ir timer and num_compressed counter */
context->num_compressed = 0;
ipnet_timeout_cancel(context->retx_ir);
ipnet_timeout_schedule(1000 * iprohc.f_max_time,
iprohc_retx_ir_timeout,
(void *)context,
&context->retx_ir);
}
break;
case ROHC_PKT_IR_DYN:
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_c_compress, format an IR-DYN packet\n");
#endif
retval = iprohc_fmt_udp_ip_irdyn(context, pkt);
if (retval == IPCOM_SUCCESS)
{
/* Increase compressed packet counter, and reset IR counter */
context->num_compressed ++;
context->num_ir = 0;
}
break;
case ROHC_PKT_TYPE_0:
case ROHC_PKT_TYPE_1:
case ROHC_PKT_TYPE_2:
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_c_compress, format packet type %s\n",
iprohc_pkt_type(context->pkt_type));
#endif
retval = iprohc_fmt_udp_ip_general(context, pkt);
if (retval == IPCOM_SUCCESS)
{
/* Increase compressed packet counter, and reset IR counter */
context->num_compressed ++;
context->num_ir = 0;
}
break;
default:
IPCOM_LOG0(ERR, "iprohc_udp_ip_c_compress: illegal packet type");
break;
}
/* Check the number of consecutive compressed packet counter */
if (context->num_compressed >= iprohc.f_max_period)
{
/* send an IR packet */
context->pkt_type = ROHC_PKT_IR;
context->num_compressed = 0;
}
/* Reset pkt type, extension type, and add_dynamic_chain flag */
if (((context->pkt_type != ROHC_PKT_IR) &&
(context->trans != ROHC_COMP_TRANS_PENDING)) ||
((context->pkt_type == ROHC_PKT_IR) &&
(context->trans != ROHC_COMP_TRANS_PENDING) &&
(context->state != ROHC_COMP_STATE_IR)))
context->pkt_type = ROHC_PKT_TYPE_0;
if (context->trans != ROHC_COMP_TRANS_PENDING)
context->ext_type = ROHC_EXT_NO_EXT;
ip_context->add_dynamic_chain = IP_FALSE;
IPROHC_C_CONTEXT_UNLOCK(context);
#ifdef DEBUG
/*
ipcom_printf("End of iprohc_udp_ip_c_compress\n");
iprohc_c_print_a_context(context);
*/
#endif
return retval;
}
/*
*===========================================================================
* iprohc_udp_ip_d_find_context
*===========================================================================
* Description: Find a decompression context associated with the packet.
*
* Passed in packet has the following general format:
* RFC 3095, 5.2
*
* --------------------------
* : Add-CID octet : if (CID 1-15) and (small CIDs)
* --------------------------
* | type indication | body |
* --------------------------
* : :
* / 0 - 2 octets of CID / 1 or 2 octets if (large CIDs)
* : :
* --------------------------
* / Body / variable length
* --------------------------
*
* Parameters:
* Returns:
*
*/
IP_PUBLIC Iprohc_d_context *
iprohc_udp_ip_d_find_context(Iprohc_decompressor *decomp, Ipcom_pkt *pkt)
{
return iprohc_ip_d_find_context(decomp, pkt);
}
/*
*===========================================================================
* iprohc_udp_ip_d_create_context
*===========================================================================
* Description: Create a decompression context for the packet.
*
* Passed in packet is an IR packet, has the following format:
* RFC 3095, 5.7.7.1, 5.11.1
*
* ---------------------------
* | Add-CID octet | if for small CIDs and CID != 0
* ---------------------------
* | 1 1 1 1 1 1 0 | D |
* ---------------------------
* | |
* / 0-2 octets of CID info / 1-2 octets if for large CIDs
* | |
* ---------------------------
* | Profile | 1 octet
* ---------------------------
* | CRC | 1 octet
* ---------------------------
* | |
* | Static chain | variable length
* | |
* ---------------------------
* | |
* | Dynamic chain | present if D = 1, variable length
* | |
* ---------------------------
* | |
* | Payload | variable length
* | |
* ---------------------------
*
* Parameters:
* Returns:
*
*/
IP_PUBLIC Iprohc_d_context *
iprohc_udp_ip_d_create_context(Iprohc_decompressor *decomp,
Ipcom_pkt *pkt)
{
Iprohc_d_context *d_context = IP_NULL;
Iprohc_d_ip_context *ip_context;
Iprohc_d_udp_context *udp_context;
Ip_u16 cid = 0;
int pointer;
Ip_u8 type_data, crc; /* to get D bit */
Iprohc_ip_header *ip_header;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_udp_ip_d_create_context\n");
#endif
/* pointer will be moved to point Profile */
IPROHC_GET_CID(pkt, pointer, cid, type_data);
/* skip profile octet */
pointer++;
/* Record CRC from the packet */
crc = pkt->data[pointer];
pointer++;
IPROHC_DECOMP_LOCK(decomp);
d_context = iprohc_d_context_common_create(cid);
if (d_context == IP_NULL)
{
IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, failed to create context");
goto errout;
}
IPROHC_D_CONTEXT_LOCK(d_context);
/* Record decompressor and CRC */
d_context->decompressor = (struct Iprohc_decompressor *)decomp;
d_context->profileid = ROHC_PROFILE_UDP_IP;
d_context->crc = crc;
/* Create profile specific context structure */
d_context->profile_context = ipcom_malloc(sizeof(Iprohc_d_udp_ip_context));
if (d_context->profile_context == IP_NULL)
{
IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, out of memory(p context)");
goto errout;
}
ipcom_memset(d_context->profile_context, 0, sizeof(Iprohc_d_udp_ip_context));
/* Create IP profile specific context structure */
ip_context = ipcom_malloc(sizeof(Iprohc_d_ip_context));
if (ip_context == IP_NULL)
{
IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, out of memory(p context)");
goto errout;
}
ipcom_memset(ip_context, 0, sizeof(Iprohc_d_ip_context));
((Iprohc_d_udp_ip_context *) d_context->profile_context)->ip_context = ip_context;
/* Init IP header list */
ipcom_list_init(&ip_context->ip_head);
/* Create UDP profile specific context structure */
udp_context = ipcom_malloc(sizeof(Iprohc_d_udp_context));
if (udp_context == IP_NULL)
{
IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, out of memory(p context)");
goto errout;
}
ipcom_memset(udp_context, 0, sizeof(Iprohc_d_udp_context));
((Iprohc_d_udp_ip_context *) d_context->profile_context)->udp_context = udp_context;
/* Init udp context */
(void) iprohc_udp_d_init(udp_context);
/* Parsing static chain to form IP headers */
IPROHC_GET_IP_STATIC(ip_context, pointer, pkt);
/* Get UDP static chain */
IPROHC_GET_UDP_STATIC(udp_context, pointer, pkt)
/* if D bit is set, parse dynamic chain */
if (type_data & 0x01)
{
IPROHC_GET_IP_DYNAMIC(ip_context, pointer, pkt);
IPROHC_GET_UDP_DYNAMIC(udp_context, pointer, pkt);
}
/* Record stream type, source and destination address */
ip_header = IPCOM_LIST_FIRST(&(ip_context->ip_head));
if (ip_header == IP_NULL)
{
IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, NULL ip_header(p context)");
goto errout;
}
d_context->stream_type = ip_header->packet_type;
#ifdef IPCOM_USE_INET
if (ip_header->packet_type == ROHC_PKT_IPV4)
{
/* An IPv4 packet */
d_context->src.addr4 = ip_header->header.ip4.src;
d_context->dst.addr4 = ip_header->header.ip4.dst;
}
#ifdef IPCOM_USE_INET6
else
#endif
#endif /* #ifdef IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
if (ip_header->packet_type == ROHC_PKT_IPV6)
{
/* An IPv6 packet */
d_context->src.addr6 = ip_header->header.ip6.src;
d_context->dst.addr6 = ip_header->header.ip6.dst;
}
#endif /* #ifdef IPCOM_USE_INET6 */
/* Record SN in ip profile specific context, and init SN LSB structure */
ip_context->sn = ip_ntohs(*((Ip_u16 *)&(pkt->data[pointer])));
pointer += 2;
/* Record UDP payload */
udp_context->payload = pointer;
/* Get UDP header length */
IPROHC_GET_UDP_LENGTH(udp_context, pkt);
#ifdef IPROHC_WLSB_LSB
iprohc_init_dmp_lsb_struct(&ip_context->sn_lsb, IPROHC_LSB_INC, 0xffff);
iprohc_dmp_lsb_save_last_valid_ref(&ip_context->sn_lsb,
ip_htons(ip_context->sn));
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_d_create_context, lsb sn %d\n",
ip_htons(ip_context->sn));
#endif /* ROHC_DEBUG */
/* Update ip_id offset from sn for every IPv4 header: ip_id - sn */
IPROHC_UPD_IPID_OFFSET(ip_context);
#endif /* IPROHC_WLSB_LSB */
/* Mark the first IR to be true */
d_context->first_ir = IP_TRUE;
/* Add the de-compression context to the de-compressor */
ipcom_list_insert_last(&decomp->context_head, &d_context->context_list);
decomp->context_num++;
IPROHC_D_CONTEXT_UNLOCK(d_context);
goto leave;
errout:
/* free d_context structure */
if (d_context)
{
/* free profile specific context structure */
if (d_context->profile_context)
{
iprohc_del_udp_ip_context(d_context->profile_context, IP_FALSE);
ipcom_free(d_context->profile_context);
}
IPROHC_D_CONTEXT_UNLOCK(d_context);
iprohc_d_context_common_del(d_context);
}
d_context = IP_NULL;
leave:
IPROHC_DECOMP_UNLOCK(decomp);
return d_context;
}
/*
*===========================================================================
* iprohc_udp_ip_d_del_context
*===========================================================================
* Description: Delete a decompression context.
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
iprohc_udp_ip_d_del_context(Iprohc_d_context *context)
{
Ip_err retval = IPCOM_SUCCESS;
#ifdef ROHC_DEBUG
ipcom_printf("Enter iprohc_udp_ip_d_del_context\n");
#endif
if (context == IP_NULL)
return retval;
IPROHC_D_CONTEXT_LOCK(context);
/* Remove the context from the de-compressor */
ipcom_list_remove(&context->context_list);
/* free profile specific context structure */
if (context->profile_context)
{
iprohc_del_udp_ip_context(context->profile_context, IP_FALSE);
ipcom_free(context->profile_context);
}
IPROHC_D_CONTEXT_UNLOCK(context);
/* free context structure */
iprohc_d_context_common_del(context);
return retval;
}
/*
*===========================================================================
* iprohc_udp_ip_d_print_context
*===========================================================================
* Description: Debug: print a de-compression context.
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
iprohc_udp_ip_d_print_context(Iprohc_d_context *context)
{
Iprohc_d_ip_context *ip_context;
Iprohc_d_udp_context *udp_context;
ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context;
udp_context = ((Iprohc_d_udp_ip_context *)context->profile_context)->udp_context;
ipcom_printf(" sn (network order): %d, sn: %d\n",
ip_htons(ip_context->sn), ip_context->sn);
ipcom_printf(" ip_num: %d\n", ip_context->ip_num);
ipcom_printf(" payload_offset: %d\n",
udp_context->payload);
ipcom_printf(" udp src_port: %u\n",
ip_ntohs(udp_context->src_port));
ipcom_printf(" udp dst_port: %u\n",
ip_ntohs(udp_context->dst_port));
ipcom_printf(" udp pkt length: %u\n",
ip_ntohs(udp_context->length));
ipcom_printf(" udp checksum: %u\n",
ip_ntohs(udp_context->checksum));
ipcom_printf(" udp checksum is used: %s\n",
udp_context->use_checksum?"Yes":"No");
}
/*
*===========================================================================
* iprohc_udp_ip_d_decompress
*===========================================================================
* Description: Decompress a packet.
*
* Passed in packet has the following general format:
* RFC 3095, 5.2
*
* --------------------------
* : Add-CID octet : if (CID 1-15) and (small CIDs)
* --------------------------
* | type indication | body |
* --------------------------
* : :
* / 0 - 2 octets of CID / 1 or 2 octets if (large CIDs)
* : :
* --------------------------
* / Body / variable length
* --------------------------
*
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
iprohc_udp_ip_d_decompress(Iprohc_d_context *context,
Ipcom_pkt *pkt)
{
Ip_err retval = IPCOM_SUCCESS;
int pointer = pkt->ipstart;
Ip_u8 pkt_type = 0, type_data;
Iprohc_d_ip_context *ip_context;
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_d_decompress\n");
#endif
/* Record type data and move pointer to point to Body */
if ((pkt->data[pointer] >> ROHC_PKT_ADD_CID_SHIFT) == ROHC_PKT_ADD_CID)
{
/* small CID */
type_data = pkt->data[pointer+1];
pointer += 2;
}
else
{
/* large CID */
type_data = pkt->data[pointer];
/*
* RFC 3095, section 5.2.2: If the first bit is 0, the CID uses
* one octet. If the first bit is 1, the CID uses two octets.
*/
if ((pkt->data[pointer+1] & 0x80) == 0)
pointer += 2;
else
pointer += 3;
}
/* Parse for packet type. */
/* ROHC segmentation type was handled in the packet intercept function. */
if (type_data == ROHC_PKT_IR_DYN)
pkt_type = ROHC_PKT_IR_DYN;
else if ((type_data >> ROHC_PKT_IR_SHIFT) == ROHC_PKT_IR)
pkt_type = ROHC_PKT_IR;
else if ((type_data >> ROHC_PKT_TYPE_0_SHIFT) == ROHC_PKT_TYPE_0)
pkt_type = ROHC_PKT_TYPE_0;
else if ((type_data >> ROHC_PKT_TYPE_1_SHIFT) == ROHC_PKT_TYPE_1)
pkt_type = ROHC_PKT_TYPE_1;
else if ((type_data >> ROHC_PKT_TYPE_2_SHIFT) == ROHC_PKT_TYPE_2)
pkt_type = ROHC_PKT_TYPE_2;
#ifdef ROHC_DEBUG
ipcom_printf("iprohc_udp_ip_d_decompress, pkt_type %s\n",
iprohc_pkt_type(pkt_type));
#endif
/* Move the ipstart and start pointer to point to Body */
pkt->ipstart = pkt->start = pointer;
IPROHC_D_CONTEXT_LOCK(context);
ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context;
/* Check whether the decompression is allowed */
IPROHC_DECOMP_ALLOWED(context, pkt_type, ip_context->sn);
/* Decompress the packet according to the packet type */
switch (pkt_type)
{
case ROHC_PKT_IR:
retval = iprohc_decomp_udp_ip_ir(context, pkt, type_data);
break;
case ROHC_PKT_IR_DYN:
retval = iprohc_decomp_udp_ip_irdyn(context, pkt, type_data);
break;
case ROHC_PKT_TYPE_0:
case ROHC_PKT_TYPE_1:
case ROHC_PKT_TYPE_2:
retval = iprohc_decomp_udp_ip_general(context, pkt, pkt_type, type_data);
break;
default:
retval = IPCOM_ERR_NOT_SUPPORTED;
IPCOM_LOG0(ERR, "iprohc_udp_ip_d_decompress: illegal packet type");
break;
}
errout:
IPROHC_D_CONTEXT_UNLOCK(context);
return retval;
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/