* Copyright (c) 2022 Huawei Device Co., Ltd.
*
* Description: This file implements the function
* of decapsulating the NewIP protocol header.
*
* Author: Yang Yanjun <yangyanjun@huawei.com>
*
* Data: 2022-07-18
*/
#include "nip_hdr.h"
static int _get_nip_hdr_bitmap(struct nip_buff *nbuf,
unsigned char bitmap[],
unsigned char bitmap_index_max)
{
int i = 0;
if (nbuf->remaining_len < sizeof(unsigned char))
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
if (*nbuf->data & NIP_BITMAP_INVALID_SET)
return -NIP_HDR_BITMAP_INVALID;
do {
if (i >= bitmap_index_max)
return -NIP_HDR_BITMAP_NUM_OUT_RANGE;
if (nbuf->remaining_len < sizeof(unsigned char))
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
bitmap[i] = *nbuf->data;
nip_buff_pull(nbuf, sizeof(unsigned char));
} while (bitmap[i++] & NIP_BITMAP_HAVE_MORE_BIT);
return i;
}
static int _get_nip_hdr_ttl(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
if (!(bitmap & NIP_BITMAP_INCLUDE_TTL))
return -NIP_HDR_NO_TTL;
if (nbuf->remaining_len < sizeof(niph->ttl))
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
niph->ttl = *nbuf->data;
niph->include_ttl = 1;
nip_buff_pull(nbuf, sizeof(niph->ttl));
return 0;
}
* but communication between devices of different versions must carry packet header length
*/
static int _get_nip_hdr_len(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
if (!(bitmap & NIP_BITMAP_INCLUDE_HDR_LEN))
return 0;
if (nbuf->remaining_len < sizeof(niph->hdr_len))
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
* compared directly with the local sequence
*/
niph->hdr_len = *nbuf->data;
niph->include_hdr_len = 1;
nip_buff_pull(nbuf, sizeof(niph->hdr_len));
if (niph->include_total_len && niph->hdr_len >= niph->rcv_buf_len)
return -NIP_HDR_LEN_OUT_RANGE;
return 0;
}
static int _get_nip_hdr_nexthdr(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
if (!(bitmap & NIP_BITMAP_INCLUDE_NEXT_HDR))
return -NIP_HDR_NO_NEXT_HDR;
if (nbuf->remaining_len < sizeof(niph->nexthdr))
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
niph->nexthdr = *nbuf->data;
niph->include_nexthdr = 1;
nip_buff_pull(nbuf, sizeof(niph->nexthdr));
return 0;
}
static int _get_nip_hdr_daddr(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
unsigned char *p;
if (!(bitmap & NIP_BITMAP_INCLUDE_DADDR))
return -NIP_HDR_NO_DADDR;
p = decode_nip_addr(nbuf, &niph->daddr);
if (!p)
return -NIP_HDR_DECAP_DADDR_ERR;
if (nip_addr_invalid(&niph->daddr))
return -NIP_HDR_DADDR_INVALID;
niph->include_daddr = 1;
return 0;
}
static int _get_nip_hdr_saddr(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
unsigned char *p;
if (!(bitmap & NIP_BITMAP_INCLUDE_SADDR))
return 0;
p = decode_nip_addr(nbuf, &niph->saddr);
if (!p)
return -NIP_HDR_DECAP_SADDR_ERR;
if (nip_addr_invalid(&niph->saddr))
return -NIP_HDR_SADDR_INVALID;
niph->include_saddr = 1;
return 0;
}
static int _get_nip_total_len(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
if (!(bitmap & NIP_BITMAP_INCLUDE_TOTAL_LEN))
return 0;
if (nbuf->remaining_len < sizeof(niph->total_len))
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
* compared directly with the local sequence
*/
niph->total_len = *((unsigned short *)nbuf->data);
niph->include_total_len = 1;
nip_buff_pull(nbuf, sizeof(niph->total_len));
return 0;
}
static int _nip_hdr_bitmap0_parse(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
int err;
err = _get_nip_hdr_ttl(nbuf, bitmap, niph);
if (err < 0)
return err;
err = _get_nip_total_len(nbuf, bitmap, niph);
if (err < 0)
return err;
err = _get_nip_hdr_nexthdr(nbuf, bitmap, niph);
if (err < 0)
return err;
err = _get_nip_hdr_daddr(nbuf, bitmap, niph);
if (err < 0)
return err;
err = _get_nip_hdr_saddr(nbuf, bitmap, niph);
if (err < 0)
return err;
return 0;
}
static int _nip_hdr_bitmap1_parse(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
int err;
if (bitmap & NIP_INVALID_BITMAP_2)
niph->include_unknown_bit = 1;
err = _get_nip_hdr_len(nbuf, bitmap, niph);
if (err < 0)
return err;
return 0;
}
static int _nip_hdr_unknown_bit_check(struct nip_buff *nbuf,
unsigned char bitmap,
struct nip_hdr_decap *niph)
{
niph->include_unknown_bit = 1;
return 0;
}
#define FACTORY_NUM_MAX 3
static int (*hdr_parse_factory[FACTORY_NUM_MAX])(struct nip_buff *,
unsigned char,
struct nip_hdr_decap *) = {
_nip_hdr_bitmap0_parse,
_nip_hdr_bitmap1_parse,
_nip_hdr_unknown_bit_check,
};
static int nip_hdr_check(struct nip_hdr_decap *niph)
{
if (niph->include_unknown_bit && !niph->include_hdr_len)
return -NIP_HDR_UNKNOWN_AND_NO_HDR_LEN;
if (niph->include_hdr_len) {
if (niph->hdr_len == 0 ||
niph->hdr_len < niph->hdr_real_len)
return -NIP_HDR_LEN_INVALID;
}
return 0;
}
* 1.niph->total_len is network order.(big end), need change to host order
* 2.niph->saddr/daddr is network order.(big end)
*/
int nip_hdr_parse(unsigned char *rcv_buf, unsigned int buf_len, struct nip_hdr_decap *niph)
{
int i = 0;
int ret;
unsigned char bitmap[BITMAP_MAX] = {0};
int num;
struct nip_buff nbuf;
nbuf.data = rcv_buf;
if (!nbuf.data)
return 0;
nbuf.remaining_len = buf_len;
num = _get_nip_hdr_bitmap(&nbuf, bitmap, BITMAP_MAX);
if (num <= 0)
return num;
niph->rcv_buf_len = buf_len;
while (i < num) {
int err;
if (i >= FACTORY_NUM_MAX)
break;
err = hdr_parse_factory[i](&nbuf, bitmap[i], niph);
if (err < 0)
return err;
i++;
}
if (buf_len < nbuf.remaining_len)
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
niph->hdr_real_len = (unsigned char)(buf_len - nbuf.remaining_len);
ret = nip_hdr_check(niph);
if (ret < 0)
return ret;
return niph->hdr_len > niph->hdr_real_len ?
niph->hdr_len : niph->hdr_real_len;
}