• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2022 Huawei Device Co., Ltd.
4  *
5  * Description: Provides some functionalities for
6  * checksum calculation in the NewIP protocol.
7  *
8  * Author: Yang Yanjun <yangyanjun@huawei.com>
9  *
10  * Data: 2022-07-18
11  */
12 #include "nip_hdr.h"
13 #include "nip_checksum.h"
14 
15 #define USHORT_PAYLOAD 16
16 #define NIP_CHECKSUM_UINT8_PAYLOAD 8
_nip_check_sum(const unsigned char * data,unsigned short data_len)17 unsigned int _nip_check_sum(const unsigned char *data, unsigned short data_len)
18 {
19 	unsigned int i = 0;
20 	unsigned int sum = 0;
21 
22 	while (i + 1 < data_len) {
23 		sum += (data[i] << NIP_CHECKSUM_UINT8_PAYLOAD) + data[i + 1];
24 		i += 2; /* Offset 2 bytes */
25 	}
26 
27 	if (i < (unsigned int)data_len)
28 		sum += (data[i] << NIP_CHECKSUM_UINT8_PAYLOAD);
29 
30 	return sum;
31 }
32 
_nip_header_chksum(struct nip_pseudo_header * chksum_header)33 unsigned int _nip_header_chksum(struct nip_pseudo_header *chksum_header)
34 {
35 	int i, j;
36 	int addr_len;
37 	unsigned char pseudo_header[NIP_HDR_MAX] = {0};
38 	unsigned short hdr_len = 0;
39 
40 	addr_len = chksum_header->saddr.bitlen / NIP_ADDR_BIT_LEN_8;
41 	if (addr_len && addr_len < NIP_HDR_MAX) {
42 		j = 0;
43 		for (i = 0; i < addr_len; i++, j++)
44 			pseudo_header[j] = chksum_header->saddr.NIP_ADDR_FIELD8[i];
45 		hdr_len += addr_len;
46 	}
47 
48 	addr_len = chksum_header->daddr.bitlen / NIP_ADDR_BIT_LEN_8;
49 	if (addr_len && addr_len < NIP_HDR_MAX) {
50 		j = hdr_len;
51 		for (i = 0; i < addr_len; i++, j++)
52 			pseudo_header[j] = chksum_header->daddr.NIP_ADDR_FIELD8[i];
53 		hdr_len += addr_len;
54 	}
55 
56 	/* chksum_header->check_len is network order.(big end) */
57 	if (hdr_len < NIP_HDR_MAX) {
58 		*(unsigned short *)(pseudo_header + hdr_len) = chksum_header->check_len;
59 		hdr_len += sizeof(chksum_header->check_len);
60 	}
61 
62 	if (hdr_len < NIP_HDR_MAX) {
63 		*(pseudo_header + hdr_len) = chksum_header->nexthdr;
64 		hdr_len += sizeof(chksum_header->nexthdr);
65 	}
66 
67 	return _nip_check_sum(pseudo_header, hdr_len);
68 }
69 
70 /* The checksum is calculated when the packet is received
71  * Note:
72  * 1.chksum_header->check_len is network order.(big end)
73  * 2.check_len is host order.
74  */
nip_check_sum_parse(unsigned char * data,unsigned short check_len,struct nip_pseudo_header * chksum_header)75 unsigned short nip_check_sum_parse(unsigned char *data,
76 				   unsigned short check_len,
77 				   struct nip_pseudo_header *chksum_header)
78 {
79 	unsigned int sum = 0;
80 
81 	sum = _nip_check_sum(data, check_len);
82 	sum += _nip_header_chksum(chksum_header);
83 
84 	while (sum >> USHORT_PAYLOAD)
85 		sum = (sum >> USHORT_PAYLOAD) + (sum & 0xffff);
86 	return (unsigned short)sum;
87 }
88 
89 /* The checksum is calculated when the packet is sent
90  * Note:
91  * 1.chksum_header->check_len is network order.(big end)
92  * 2.data_len is host order.
93  */
nip_check_sum_build(unsigned char * data,unsigned short data_len,struct nip_pseudo_header * chksum_header)94 unsigned short nip_check_sum_build(unsigned char *data,
95 				   unsigned short data_len,
96 				   struct nip_pseudo_header *chksum_header)
97 {
98 	unsigned int sum = 0;
99 
100 	sum = _nip_check_sum(data, data_len);
101 	sum += _nip_header_chksum(chksum_header);
102 
103 	while (sum >> USHORT_PAYLOAD)
104 		sum = (sum >> USHORT_PAYLOAD) + (sum & 0xffff);
105 	return (unsigned short)(~sum);
106 }
107 
108