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 17unsigned 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 33unsigned 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 */ 75unsigned 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 */ 94unsigned 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