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