2747 lines
85 KiB
C
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
|
|
****************************************************************************
|
|
*/
|