cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ud_header.c (14578B)


      1/*
      2 * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
      3 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
      4 *
      5 * This software is available to you under a choice of one of two
      6 * licenses.  You may choose to be licensed under the terms of the GNU
      7 * General Public License (GPL) Version 2, available from the file
      8 * COPYING in the main directory of this source tree, or the
      9 * OpenIB.org BSD license below:
     10 *
     11 *     Redistribution and use in source and binary forms, with or
     12 *     without modification, are permitted provided that the following
     13 *     conditions are met:
     14 *
     15 *      - Redistributions of source code must retain the above
     16 *        copyright notice, this list of conditions and the following
     17 *        disclaimer.
     18 *
     19 *      - Redistributions in binary form must reproduce the above
     20 *        copyright notice, this list of conditions and the following
     21 *        disclaimer in the documentation and/or other materials
     22 *        provided with the distribution.
     23 *
     24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     31 * SOFTWARE.
     32 */
     33
     34#include <linux/errno.h>
     35#include <linux/string.h>
     36#include <linux/export.h>
     37#include <linux/if_ether.h>
     38#include <linux/ip.h>
     39
     40#include <rdma/ib_pack.h>
     41
     42#define STRUCT_FIELD(header, field) \
     43	.struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field),      \
     44	.struct_size_bytes   = sizeof_field(struct ib_unpacked_ ## header, field), \
     45	.field_name          = #header ":" #field
     46
     47static const struct ib_field lrh_table[]  = {
     48	{ STRUCT_FIELD(lrh, virtual_lane),
     49	  .offset_words = 0,
     50	  .offset_bits  = 0,
     51	  .size_bits    = 4 },
     52	{ STRUCT_FIELD(lrh, link_version),
     53	  .offset_words = 0,
     54	  .offset_bits  = 4,
     55	  .size_bits    = 4 },
     56	{ STRUCT_FIELD(lrh, service_level),
     57	  .offset_words = 0,
     58	  .offset_bits  = 8,
     59	  .size_bits    = 4 },
     60	{ RESERVED,
     61	  .offset_words = 0,
     62	  .offset_bits  = 12,
     63	  .size_bits    = 2 },
     64	{ STRUCT_FIELD(lrh, link_next_header),
     65	  .offset_words = 0,
     66	  .offset_bits  = 14,
     67	  .size_bits    = 2 },
     68	{ STRUCT_FIELD(lrh, destination_lid),
     69	  .offset_words = 0,
     70	  .offset_bits  = 16,
     71	  .size_bits    = 16 },
     72	{ RESERVED,
     73	  .offset_words = 1,
     74	  .offset_bits  = 0,
     75	  .size_bits    = 5 },
     76	{ STRUCT_FIELD(lrh, packet_length),
     77	  .offset_words = 1,
     78	  .offset_bits  = 5,
     79	  .size_bits    = 11 },
     80	{ STRUCT_FIELD(lrh, source_lid),
     81	  .offset_words = 1,
     82	  .offset_bits  = 16,
     83	  .size_bits    = 16 }
     84};
     85
     86static const struct ib_field eth_table[]  = {
     87	{ STRUCT_FIELD(eth, dmac_h),
     88	  .offset_words = 0,
     89	  .offset_bits  = 0,
     90	  .size_bits    = 32 },
     91	{ STRUCT_FIELD(eth, dmac_l),
     92	  .offset_words = 1,
     93	  .offset_bits  = 0,
     94	  .size_bits    = 16 },
     95	{ STRUCT_FIELD(eth, smac_h),
     96	  .offset_words = 1,
     97	  .offset_bits  = 16,
     98	  .size_bits    = 16 },
     99	{ STRUCT_FIELD(eth, smac_l),
    100	  .offset_words = 2,
    101	  .offset_bits  = 0,
    102	  .size_bits    = 32 },
    103	{ STRUCT_FIELD(eth, type),
    104	  .offset_words = 3,
    105	  .offset_bits  = 0,
    106	  .size_bits    = 16 }
    107};
    108
    109static const struct ib_field vlan_table[]  = {
    110	{ STRUCT_FIELD(vlan, tag),
    111	  .offset_words = 0,
    112	  .offset_bits  = 0,
    113	  .size_bits    = 16 },
    114	{ STRUCT_FIELD(vlan, type),
    115	  .offset_words = 0,
    116	  .offset_bits  = 16,
    117	  .size_bits    = 16 }
    118};
    119
    120static const struct ib_field ip4_table[]  = {
    121	{ STRUCT_FIELD(ip4, ver),
    122	  .offset_words = 0,
    123	  .offset_bits  = 0,
    124	  .size_bits    = 4 },
    125	{ STRUCT_FIELD(ip4, hdr_len),
    126	  .offset_words = 0,
    127	  .offset_bits  = 4,
    128	  .size_bits    = 4 },
    129	{ STRUCT_FIELD(ip4, tos),
    130	  .offset_words = 0,
    131	  .offset_bits  = 8,
    132	  .size_bits    = 8 },
    133	{ STRUCT_FIELD(ip4, tot_len),
    134	  .offset_words = 0,
    135	  .offset_bits  = 16,
    136	  .size_bits    = 16 },
    137	{ STRUCT_FIELD(ip4, id),
    138	  .offset_words = 1,
    139	  .offset_bits  = 0,
    140	  .size_bits    = 16 },
    141	{ STRUCT_FIELD(ip4, frag_off),
    142	  .offset_words = 1,
    143	  .offset_bits  = 16,
    144	  .size_bits    = 16 },
    145	{ STRUCT_FIELD(ip4, ttl),
    146	  .offset_words = 2,
    147	  .offset_bits  = 0,
    148	  .size_bits    = 8 },
    149	{ STRUCT_FIELD(ip4, protocol),
    150	  .offset_words = 2,
    151	  .offset_bits  = 8,
    152	  .size_bits    = 8 },
    153	{ STRUCT_FIELD(ip4, check),
    154	  .offset_words = 2,
    155	  .offset_bits  = 16,
    156	  .size_bits    = 16 },
    157	{ STRUCT_FIELD(ip4, saddr),
    158	  .offset_words = 3,
    159	  .offset_bits  = 0,
    160	  .size_bits    = 32 },
    161	{ STRUCT_FIELD(ip4, daddr),
    162	  .offset_words = 4,
    163	  .offset_bits  = 0,
    164	  .size_bits    = 32 }
    165};
    166
    167static const struct ib_field udp_table[]  = {
    168	{ STRUCT_FIELD(udp, sport),
    169	  .offset_words = 0,
    170	  .offset_bits  = 0,
    171	  .size_bits    = 16 },
    172	{ STRUCT_FIELD(udp, dport),
    173	  .offset_words = 0,
    174	  .offset_bits  = 16,
    175	  .size_bits    = 16 },
    176	{ STRUCT_FIELD(udp, length),
    177	  .offset_words = 1,
    178	  .offset_bits  = 0,
    179	  .size_bits    = 16 },
    180	{ STRUCT_FIELD(udp, csum),
    181	  .offset_words = 1,
    182	  .offset_bits  = 16,
    183	  .size_bits    = 16 }
    184};
    185
    186static const struct ib_field grh_table[]  = {
    187	{ STRUCT_FIELD(grh, ip_version),
    188	  .offset_words = 0,
    189	  .offset_bits  = 0,
    190	  .size_bits    = 4 },
    191	{ STRUCT_FIELD(grh, traffic_class),
    192	  .offset_words = 0,
    193	  .offset_bits  = 4,
    194	  .size_bits    = 8 },
    195	{ STRUCT_FIELD(grh, flow_label),
    196	  .offset_words = 0,
    197	  .offset_bits  = 12,
    198	  .size_bits    = 20 },
    199	{ STRUCT_FIELD(grh, payload_length),
    200	  .offset_words = 1,
    201	  .offset_bits  = 0,
    202	  .size_bits    = 16 },
    203	{ STRUCT_FIELD(grh, next_header),
    204	  .offset_words = 1,
    205	  .offset_bits  = 16,
    206	  .size_bits    = 8 },
    207	{ STRUCT_FIELD(grh, hop_limit),
    208	  .offset_words = 1,
    209	  .offset_bits  = 24,
    210	  .size_bits    = 8 },
    211	{ STRUCT_FIELD(grh, source_gid),
    212	  .offset_words = 2,
    213	  .offset_bits  = 0,
    214	  .size_bits    = 128 },
    215	{ STRUCT_FIELD(grh, destination_gid),
    216	  .offset_words = 6,
    217	  .offset_bits  = 0,
    218	  .size_bits    = 128 }
    219};
    220
    221static const struct ib_field bth_table[]  = {
    222	{ STRUCT_FIELD(bth, opcode),
    223	  .offset_words = 0,
    224	  .offset_bits  = 0,
    225	  .size_bits    = 8 },
    226	{ STRUCT_FIELD(bth, solicited_event),
    227	  .offset_words = 0,
    228	  .offset_bits  = 8,
    229	  .size_bits    = 1 },
    230	{ STRUCT_FIELD(bth, mig_req),
    231	  .offset_words = 0,
    232	  .offset_bits  = 9,
    233	  .size_bits    = 1 },
    234	{ STRUCT_FIELD(bth, pad_count),
    235	  .offset_words = 0,
    236	  .offset_bits  = 10,
    237	  .size_bits    = 2 },
    238	{ STRUCT_FIELD(bth, transport_header_version),
    239	  .offset_words = 0,
    240	  .offset_bits  = 12,
    241	  .size_bits    = 4 },
    242	{ STRUCT_FIELD(bth, pkey),
    243	  .offset_words = 0,
    244	  .offset_bits  = 16,
    245	  .size_bits    = 16 },
    246	{ RESERVED,
    247	  .offset_words = 1,
    248	  .offset_bits  = 0,
    249	  .size_bits    = 8 },
    250	{ STRUCT_FIELD(bth, destination_qpn),
    251	  .offset_words = 1,
    252	  .offset_bits  = 8,
    253	  .size_bits    = 24 },
    254	{ STRUCT_FIELD(bth, ack_req),
    255	  .offset_words = 2,
    256	  .offset_bits  = 0,
    257	  .size_bits    = 1 },
    258	{ RESERVED,
    259	  .offset_words = 2,
    260	  .offset_bits  = 1,
    261	  .size_bits    = 7 },
    262	{ STRUCT_FIELD(bth, psn),
    263	  .offset_words = 2,
    264	  .offset_bits  = 8,
    265	  .size_bits    = 24 }
    266};
    267
    268static const struct ib_field deth_table[] = {
    269	{ STRUCT_FIELD(deth, qkey),
    270	  .offset_words = 0,
    271	  .offset_bits  = 0,
    272	  .size_bits    = 32 },
    273	{ RESERVED,
    274	  .offset_words = 1,
    275	  .offset_bits  = 0,
    276	  .size_bits    = 8 },
    277	{ STRUCT_FIELD(deth, source_qpn),
    278	  .offset_words = 1,
    279	  .offset_bits  = 8,
    280	  .size_bits    = 24 }
    281};
    282
    283__sum16 ib_ud_ip4_csum(struct ib_ud_header *header)
    284{
    285	struct iphdr iph;
    286
    287	iph.ihl		= 5;
    288	iph.version	= 4;
    289	iph.tos		= header->ip4.tos;
    290	iph.tot_len	= header->ip4.tot_len;
    291	iph.id		= header->ip4.id;
    292	iph.frag_off	= header->ip4.frag_off;
    293	iph.ttl		= header->ip4.ttl;
    294	iph.protocol	= header->ip4.protocol;
    295	iph.check	= 0;
    296	iph.saddr	= header->ip4.saddr;
    297	iph.daddr	= header->ip4.daddr;
    298
    299	return ip_fast_csum((u8 *)&iph, iph.ihl);
    300}
    301EXPORT_SYMBOL(ib_ud_ip4_csum);
    302
    303/**
    304 * ib_ud_header_init - Initialize UD header structure
    305 * @payload_bytes:Length of packet payload
    306 * @lrh_present: specify if LRH is present
    307 * @eth_present: specify if Eth header is present
    308 * @vlan_present: packet is tagged vlan
    309 * @grh_present: GRH flag (if non-zero, GRH will be included)
    310 * @ip_version: if non-zero, IP header, V4 or V6, will be included
    311 * @udp_present :if non-zero, UDP header will be included
    312 * @immediate_present: specify if immediate data is present
    313 * @header:Structure to initialize
    314 */
    315int ib_ud_header_init(int     payload_bytes,
    316		      int    lrh_present,
    317		      int    eth_present,
    318		      int    vlan_present,
    319		      int    grh_present,
    320		      int    ip_version,
    321		      int    udp_present,
    322		      int    immediate_present,
    323		      struct ib_ud_header *header)
    324{
    325	size_t udp_bytes = udp_present ? IB_UDP_BYTES : 0;
    326
    327	grh_present = grh_present && !ip_version;
    328	memset(header, 0, sizeof *header);
    329
    330	/*
    331	 * UDP header without IP header doesn't make sense
    332	 */
    333	if (udp_present && ip_version != 4 && ip_version != 6)
    334		return -EINVAL;
    335
    336	if (lrh_present) {
    337		u16 packet_length;
    338
    339		header->lrh.link_version     = 0;
    340		header->lrh.link_next_header =
    341			grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
    342		packet_length = (IB_LRH_BYTES	+
    343				 IB_BTH_BYTES	+
    344				 IB_DETH_BYTES	+
    345				 (grh_present ? IB_GRH_BYTES : 0) +
    346				 payload_bytes	+
    347				 4		+ /* ICRC     */
    348				 3) / 4;	  /* round up */
    349		header->lrh.packet_length = cpu_to_be16(packet_length);
    350	}
    351
    352	if (vlan_present)
    353		header->eth.type = cpu_to_be16(ETH_P_8021Q);
    354
    355	if (ip_version == 6 || grh_present) {
    356		header->grh.ip_version      = 6;
    357		header->grh.payload_length  =
    358			cpu_to_be16((udp_bytes        +
    359				     IB_BTH_BYTES     +
    360				     IB_DETH_BYTES    +
    361				     payload_bytes    +
    362				     4                + /* ICRC     */
    363				     3) & ~3);          /* round up */
    364		header->grh.next_header     = udp_present ? IPPROTO_UDP : 0x1b;
    365	}
    366
    367	if (ip_version == 4) {
    368		header->ip4.ver = 4; /* version 4 */
    369		header->ip4.hdr_len = 5; /* 5 words */
    370		header->ip4.tot_len =
    371			cpu_to_be16(IB_IP4_BYTES   +
    372				     udp_bytes     +
    373				     IB_BTH_BYTES  +
    374				     IB_DETH_BYTES +
    375				     payload_bytes +
    376				     4);     /* ICRC     */
    377		header->ip4.protocol = IPPROTO_UDP;
    378	}
    379	if (udp_present && ip_version)
    380		header->udp.length =
    381			cpu_to_be16(IB_UDP_BYTES   +
    382				     IB_BTH_BYTES  +
    383				     IB_DETH_BYTES +
    384				     payload_bytes +
    385				     4);     /* ICRC     */
    386
    387	if (immediate_present)
    388		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
    389	else
    390		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY;
    391	header->bth.pad_count                = (4 - payload_bytes) & 3;
    392	header->bth.transport_header_version = 0;
    393
    394	header->lrh_present = lrh_present;
    395	header->eth_present = eth_present;
    396	header->vlan_present = vlan_present;
    397	header->grh_present = grh_present || (ip_version == 6);
    398	header->ipv4_present = ip_version == 4;
    399	header->udp_present = udp_present;
    400	header->immediate_present = immediate_present;
    401	return 0;
    402}
    403EXPORT_SYMBOL(ib_ud_header_init);
    404
    405/**
    406 * ib_ud_header_pack - Pack UD header struct into wire format
    407 * @header:UD header struct
    408 * @buf:Buffer to pack into
    409 *
    410 * ib_ud_header_pack() packs the UD header structure @header into wire
    411 * format in the buffer @buf.
    412 */
    413int ib_ud_header_pack(struct ib_ud_header *header,
    414		      void                *buf)
    415{
    416	int len = 0;
    417
    418	if (header->lrh_present) {
    419		ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
    420			&header->lrh, buf + len);
    421		len += IB_LRH_BYTES;
    422	}
    423	if (header->eth_present) {
    424		ib_pack(eth_table, ARRAY_SIZE(eth_table),
    425			&header->eth, buf + len);
    426		len += IB_ETH_BYTES;
    427	}
    428	if (header->vlan_present) {
    429		ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
    430			&header->vlan, buf + len);
    431		len += IB_VLAN_BYTES;
    432	}
    433	if (header->grh_present) {
    434		ib_pack(grh_table, ARRAY_SIZE(grh_table),
    435			&header->grh, buf + len);
    436		len += IB_GRH_BYTES;
    437	}
    438	if (header->ipv4_present) {
    439		ib_pack(ip4_table, ARRAY_SIZE(ip4_table),
    440			&header->ip4, buf + len);
    441		len += IB_IP4_BYTES;
    442	}
    443	if (header->udp_present) {
    444		ib_pack(udp_table, ARRAY_SIZE(udp_table),
    445			&header->udp, buf + len);
    446		len += IB_UDP_BYTES;
    447	}
    448
    449	ib_pack(bth_table, ARRAY_SIZE(bth_table),
    450		&header->bth, buf + len);
    451	len += IB_BTH_BYTES;
    452
    453	ib_pack(deth_table, ARRAY_SIZE(deth_table),
    454		&header->deth, buf + len);
    455	len += IB_DETH_BYTES;
    456
    457	if (header->immediate_present) {
    458		memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data);
    459		len += sizeof header->immediate_data;
    460	}
    461
    462	return len;
    463}
    464EXPORT_SYMBOL(ib_ud_header_pack);
    465
    466/**
    467 * ib_ud_header_unpack - Unpack UD header struct from wire format
    468 * @header:UD header struct
    469 * @buf:Buffer to pack into
    470 *
    471 * ib_ud_header_pack() unpacks the UD header structure @header from wire
    472 * format in the buffer @buf.
    473 */
    474int ib_ud_header_unpack(void                *buf,
    475			struct ib_ud_header *header)
    476{
    477	ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
    478		  buf, &header->lrh);
    479	buf += IB_LRH_BYTES;
    480
    481	if (header->lrh.link_version != 0) {
    482		pr_warn("Invalid LRH.link_version %u\n",
    483			header->lrh.link_version);
    484		return -EINVAL;
    485	}
    486
    487	switch (header->lrh.link_next_header) {
    488	case IB_LNH_IBA_LOCAL:
    489		header->grh_present = 0;
    490		break;
    491
    492	case IB_LNH_IBA_GLOBAL:
    493		header->grh_present = 1;
    494		ib_unpack(grh_table, ARRAY_SIZE(grh_table),
    495			  buf, &header->grh);
    496		buf += IB_GRH_BYTES;
    497
    498		if (header->grh.ip_version != 6) {
    499			pr_warn("Invalid GRH.ip_version %u\n",
    500				header->grh.ip_version);
    501			return -EINVAL;
    502		}
    503		if (header->grh.next_header != 0x1b) {
    504			pr_warn("Invalid GRH.next_header 0x%02x\n",
    505				header->grh.next_header);
    506			return -EINVAL;
    507		}
    508		break;
    509
    510	default:
    511		pr_warn("Invalid LRH.link_next_header %u\n",
    512			header->lrh.link_next_header);
    513		return -EINVAL;
    514	}
    515
    516	ib_unpack(bth_table, ARRAY_SIZE(bth_table),
    517		  buf, &header->bth);
    518	buf += IB_BTH_BYTES;
    519
    520	switch (header->bth.opcode) {
    521	case IB_OPCODE_UD_SEND_ONLY:
    522		header->immediate_present = 0;
    523		break;
    524	case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
    525		header->immediate_present = 1;
    526		break;
    527	default:
    528		pr_warn("Invalid BTH.opcode 0x%02x\n", header->bth.opcode);
    529		return -EINVAL;
    530	}
    531
    532	if (header->bth.transport_header_version != 0) {
    533		pr_warn("Invalid BTH.transport_header_version %u\n",
    534			header->bth.transport_header_version);
    535		return -EINVAL;
    536	}
    537
    538	ib_unpack(deth_table, ARRAY_SIZE(deth_table),
    539		  buf, &header->deth);
    540	buf += IB_DETH_BYTES;
    541
    542	if (header->immediate_present)
    543		memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
    544
    545	return 0;
    546}
    547EXPORT_SYMBOL(ib_ud_header_unpack);