Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/*
  3 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
  4 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
  5 */
  6
  7#include <linux/crc32.h>
  8
  9#include "rxe.h"
 10#include "rxe_loc.h"
 11
 12/**
 13 * rxe_icrc_init() - Initialize crypto function for computing crc32
 14 * @rxe: rdma_rxe device object
 15 *
 16 * Return: 0 on success else an error
 17 */
 18int rxe_icrc_init(struct rxe_dev *rxe)
 19{
 20	struct crypto_shash *tfm;
 21
 22	tfm = crypto_alloc_shash("crc32", 0, 0);
 23	if (IS_ERR(tfm)) {
 24		rxe_dbg(rxe, "failed to init crc32 algorithm err: %ld\n",
 25			       PTR_ERR(tfm));
 26		return PTR_ERR(tfm);
 27	}
 28
 29	rxe->tfm = tfm;
 30
 31	return 0;
 32}
 33
 34/**
 35 * rxe_crc32() - Compute cumulative crc32 for a contiguous segment
 36 * @rxe: rdma_rxe device object
 37 * @crc: starting crc32 value from previous segments
 38 * @next: starting address of current segment
 39 * @len: length of current segment
 40 *
 41 * Return: the cumulative crc32 checksum
 42 */
 43static __be32 rxe_crc32(struct rxe_dev *rxe, __be32 crc, void *next, size_t len)
 44{
 45	__be32 icrc;
 46	int err;
 47
 48	SHASH_DESC_ON_STACK(shash, rxe->tfm);
 49
 50	shash->tfm = rxe->tfm;
 51	*(__be32 *)shash_desc_ctx(shash) = crc;
 52	err = crypto_shash_update(shash, next, len);
 53	if (unlikely(err)) {
 54		rxe_dbg(rxe, "failed crc calculation, err: %d\n", err);
 55		return (__force __be32)crc32_le((__force u32)crc, next, len);
 56	}
 57
 58	icrc = *(__be32 *)shash_desc_ctx(shash);
 59	barrier_data(shash_desc_ctx(shash));
 60
 61	return icrc;
 62}
 63
 64/**
 65 * rxe_icrc_hdr() - Compute the partial ICRC for the network and transport
 66 *		  headers of a packet.
 67 * @skb: packet buffer
 68 * @pkt: packet information
 69 *
 70 * Return: the partial ICRC
 71 */
 72static __be32 rxe_icrc_hdr(struct sk_buff *skb, struct rxe_pkt_info *pkt)
 73{
 74	unsigned int bth_offset = 0;
 75	struct iphdr *ip4h = NULL;
 76	struct ipv6hdr *ip6h = NULL;
 77	struct udphdr *udph;
 78	struct rxe_bth *bth;
 79	__be32 crc;
 80	int length;
 81	int hdr_size = sizeof(struct udphdr) +
 82		(skb->protocol == htons(ETH_P_IP) ?
 83		sizeof(struct iphdr) : sizeof(struct ipv6hdr));
 84	/* pseudo header buffer size is calculate using ipv6 header size since
 85	 * it is bigger than ipv4
 86	 */
 87	u8 pshdr[sizeof(struct udphdr) +
 88		sizeof(struct ipv6hdr) +
 89		RXE_BTH_BYTES];
 90
 91	/* This seed is the result of computing a CRC with a seed of
 92	 * 0xfffffff and 8 bytes of 0xff representing a masked LRH.
 93	 */
 94	crc = (__force __be32)0xdebb20e3;
 95
 96	if (skb->protocol == htons(ETH_P_IP)) { /* IPv4 */
 97		memcpy(pshdr, ip_hdr(skb), hdr_size);
 98		ip4h = (struct iphdr *)pshdr;
 99		udph = (struct udphdr *)(ip4h + 1);
100
101		ip4h->ttl = 0xff;
102		ip4h->check = CSUM_MANGLED_0;
103		ip4h->tos = 0xff;
104	} else {				/* IPv6 */
105		memcpy(pshdr, ipv6_hdr(skb), hdr_size);
106		ip6h = (struct ipv6hdr *)pshdr;
107		udph = (struct udphdr *)(ip6h + 1);
108
109		memset(ip6h->flow_lbl, 0xff, sizeof(ip6h->flow_lbl));
110		ip6h->priority = 0xf;
111		ip6h->hop_limit = 0xff;
112	}
113	udph->check = CSUM_MANGLED_0;
114
115	bth_offset += hdr_size;
116
117	memcpy(&pshdr[bth_offset], pkt->hdr, RXE_BTH_BYTES);
118	bth = (struct rxe_bth *)&pshdr[bth_offset];
119
120	/* exclude bth.resv8a */
121	bth->qpn |= cpu_to_be32(~BTH_QPN_MASK);
122
123	length = hdr_size + RXE_BTH_BYTES;
124	crc = rxe_crc32(pkt->rxe, crc, pshdr, length);
125
126	/* And finish to compute the CRC on the remainder of the headers. */
127	crc = rxe_crc32(pkt->rxe, crc, pkt->hdr + RXE_BTH_BYTES,
128			rxe_opcode[pkt->opcode].length - RXE_BTH_BYTES);
129	return crc;
130}
131
132/**
133 * rxe_icrc_check() - Compute ICRC for a packet and compare to the ICRC
134 *		      delivered in the packet.
135 * @skb: packet buffer
136 * @pkt: packet information
137 *
138 * Return: 0 if the values match else an error
139 */
140int rxe_icrc_check(struct sk_buff *skb, struct rxe_pkt_info *pkt)
141{
142	__be32 *icrcp;
143	__be32 pkt_icrc;
144	__be32 icrc;
145
146	icrcp = (__be32 *)(pkt->hdr + pkt->paylen - RXE_ICRC_SIZE);
147	pkt_icrc = *icrcp;
148
149	icrc = rxe_icrc_hdr(skb, pkt);
150	icrc = rxe_crc32(pkt->rxe, icrc, (u8 *)payload_addr(pkt),
151				payload_size(pkt) + bth_pad(pkt));
152	icrc = ~icrc;
153
154	if (unlikely(icrc != pkt_icrc))
155		return -EINVAL;
156
157	return 0;
158}
159
160/**
161 * rxe_icrc_generate() - compute ICRC for a packet.
162 * @skb: packet buffer
163 * @pkt: packet information
164 */
165void rxe_icrc_generate(struct sk_buff *skb, struct rxe_pkt_info *pkt)
166{
167	__be32 *icrcp;
168	__be32 icrc;
169
170	icrcp = (__be32 *)(pkt->hdr + pkt->paylen - RXE_ICRC_SIZE);
171	icrc = rxe_icrc_hdr(skb, pkt);
172	icrc = rxe_crc32(pkt->rxe, icrc, (u8 *)payload_addr(pkt),
173				payload_size(pkt) + bth_pad(pkt));
174	*icrcp = ~icrc;
175}