0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #include <linux/errno.h>
0035 #include <linux/string.h>
0036 #include <linux/export.h>
0037 #include <linux/if_ether.h>
0038 #include <linux/ip.h>
0039
0040 #include <rdma/ib_pack.h>
0041
0042 #define STRUCT_FIELD(header, field) \
0043 .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \
0044 .struct_size_bytes = sizeof_field(struct ib_unpacked_ ## header, field), \
0045 .field_name = #header ":" #field
0046
0047 static const struct ib_field lrh_table[] = {
0048 { STRUCT_FIELD(lrh, virtual_lane),
0049 .offset_words = 0,
0050 .offset_bits = 0,
0051 .size_bits = 4 },
0052 { STRUCT_FIELD(lrh, link_version),
0053 .offset_words = 0,
0054 .offset_bits = 4,
0055 .size_bits = 4 },
0056 { STRUCT_FIELD(lrh, service_level),
0057 .offset_words = 0,
0058 .offset_bits = 8,
0059 .size_bits = 4 },
0060 { RESERVED,
0061 .offset_words = 0,
0062 .offset_bits = 12,
0063 .size_bits = 2 },
0064 { STRUCT_FIELD(lrh, link_next_header),
0065 .offset_words = 0,
0066 .offset_bits = 14,
0067 .size_bits = 2 },
0068 { STRUCT_FIELD(lrh, destination_lid),
0069 .offset_words = 0,
0070 .offset_bits = 16,
0071 .size_bits = 16 },
0072 { RESERVED,
0073 .offset_words = 1,
0074 .offset_bits = 0,
0075 .size_bits = 5 },
0076 { STRUCT_FIELD(lrh, packet_length),
0077 .offset_words = 1,
0078 .offset_bits = 5,
0079 .size_bits = 11 },
0080 { STRUCT_FIELD(lrh, source_lid),
0081 .offset_words = 1,
0082 .offset_bits = 16,
0083 .size_bits = 16 }
0084 };
0085
0086 static const struct ib_field eth_table[] = {
0087 { STRUCT_FIELD(eth, dmac_h),
0088 .offset_words = 0,
0089 .offset_bits = 0,
0090 .size_bits = 32 },
0091 { STRUCT_FIELD(eth, dmac_l),
0092 .offset_words = 1,
0093 .offset_bits = 0,
0094 .size_bits = 16 },
0095 { STRUCT_FIELD(eth, smac_h),
0096 .offset_words = 1,
0097 .offset_bits = 16,
0098 .size_bits = 16 },
0099 { STRUCT_FIELD(eth, smac_l),
0100 .offset_words = 2,
0101 .offset_bits = 0,
0102 .size_bits = 32 },
0103 { STRUCT_FIELD(eth, type),
0104 .offset_words = 3,
0105 .offset_bits = 0,
0106 .size_bits = 16 }
0107 };
0108
0109 static const struct ib_field vlan_table[] = {
0110 { STRUCT_FIELD(vlan, tag),
0111 .offset_words = 0,
0112 .offset_bits = 0,
0113 .size_bits = 16 },
0114 { STRUCT_FIELD(vlan, type),
0115 .offset_words = 0,
0116 .offset_bits = 16,
0117 .size_bits = 16 }
0118 };
0119
0120 static const struct ib_field ip4_table[] = {
0121 { STRUCT_FIELD(ip4, ver),
0122 .offset_words = 0,
0123 .offset_bits = 0,
0124 .size_bits = 4 },
0125 { STRUCT_FIELD(ip4, hdr_len),
0126 .offset_words = 0,
0127 .offset_bits = 4,
0128 .size_bits = 4 },
0129 { STRUCT_FIELD(ip4, tos),
0130 .offset_words = 0,
0131 .offset_bits = 8,
0132 .size_bits = 8 },
0133 { STRUCT_FIELD(ip4, tot_len),
0134 .offset_words = 0,
0135 .offset_bits = 16,
0136 .size_bits = 16 },
0137 { STRUCT_FIELD(ip4, id),
0138 .offset_words = 1,
0139 .offset_bits = 0,
0140 .size_bits = 16 },
0141 { STRUCT_FIELD(ip4, frag_off),
0142 .offset_words = 1,
0143 .offset_bits = 16,
0144 .size_bits = 16 },
0145 { STRUCT_FIELD(ip4, ttl),
0146 .offset_words = 2,
0147 .offset_bits = 0,
0148 .size_bits = 8 },
0149 { STRUCT_FIELD(ip4, protocol),
0150 .offset_words = 2,
0151 .offset_bits = 8,
0152 .size_bits = 8 },
0153 { STRUCT_FIELD(ip4, check),
0154 .offset_words = 2,
0155 .offset_bits = 16,
0156 .size_bits = 16 },
0157 { STRUCT_FIELD(ip4, saddr),
0158 .offset_words = 3,
0159 .offset_bits = 0,
0160 .size_bits = 32 },
0161 { STRUCT_FIELD(ip4, daddr),
0162 .offset_words = 4,
0163 .offset_bits = 0,
0164 .size_bits = 32 }
0165 };
0166
0167 static const struct ib_field udp_table[] = {
0168 { STRUCT_FIELD(udp, sport),
0169 .offset_words = 0,
0170 .offset_bits = 0,
0171 .size_bits = 16 },
0172 { STRUCT_FIELD(udp, dport),
0173 .offset_words = 0,
0174 .offset_bits = 16,
0175 .size_bits = 16 },
0176 { STRUCT_FIELD(udp, length),
0177 .offset_words = 1,
0178 .offset_bits = 0,
0179 .size_bits = 16 },
0180 { STRUCT_FIELD(udp, csum),
0181 .offset_words = 1,
0182 .offset_bits = 16,
0183 .size_bits = 16 }
0184 };
0185
0186 static const struct ib_field grh_table[] = {
0187 { STRUCT_FIELD(grh, ip_version),
0188 .offset_words = 0,
0189 .offset_bits = 0,
0190 .size_bits = 4 },
0191 { STRUCT_FIELD(grh, traffic_class),
0192 .offset_words = 0,
0193 .offset_bits = 4,
0194 .size_bits = 8 },
0195 { STRUCT_FIELD(grh, flow_label),
0196 .offset_words = 0,
0197 .offset_bits = 12,
0198 .size_bits = 20 },
0199 { STRUCT_FIELD(grh, payload_length),
0200 .offset_words = 1,
0201 .offset_bits = 0,
0202 .size_bits = 16 },
0203 { STRUCT_FIELD(grh, next_header),
0204 .offset_words = 1,
0205 .offset_bits = 16,
0206 .size_bits = 8 },
0207 { STRUCT_FIELD(grh, hop_limit),
0208 .offset_words = 1,
0209 .offset_bits = 24,
0210 .size_bits = 8 },
0211 { STRUCT_FIELD(grh, source_gid),
0212 .offset_words = 2,
0213 .offset_bits = 0,
0214 .size_bits = 128 },
0215 { STRUCT_FIELD(grh, destination_gid),
0216 .offset_words = 6,
0217 .offset_bits = 0,
0218 .size_bits = 128 }
0219 };
0220
0221 static const struct ib_field bth_table[] = {
0222 { STRUCT_FIELD(bth, opcode),
0223 .offset_words = 0,
0224 .offset_bits = 0,
0225 .size_bits = 8 },
0226 { STRUCT_FIELD(bth, solicited_event),
0227 .offset_words = 0,
0228 .offset_bits = 8,
0229 .size_bits = 1 },
0230 { STRUCT_FIELD(bth, mig_req),
0231 .offset_words = 0,
0232 .offset_bits = 9,
0233 .size_bits = 1 },
0234 { STRUCT_FIELD(bth, pad_count),
0235 .offset_words = 0,
0236 .offset_bits = 10,
0237 .size_bits = 2 },
0238 { STRUCT_FIELD(bth, transport_header_version),
0239 .offset_words = 0,
0240 .offset_bits = 12,
0241 .size_bits = 4 },
0242 { STRUCT_FIELD(bth, pkey),
0243 .offset_words = 0,
0244 .offset_bits = 16,
0245 .size_bits = 16 },
0246 { RESERVED,
0247 .offset_words = 1,
0248 .offset_bits = 0,
0249 .size_bits = 8 },
0250 { STRUCT_FIELD(bth, destination_qpn),
0251 .offset_words = 1,
0252 .offset_bits = 8,
0253 .size_bits = 24 },
0254 { STRUCT_FIELD(bth, ack_req),
0255 .offset_words = 2,
0256 .offset_bits = 0,
0257 .size_bits = 1 },
0258 { RESERVED,
0259 .offset_words = 2,
0260 .offset_bits = 1,
0261 .size_bits = 7 },
0262 { STRUCT_FIELD(bth, psn),
0263 .offset_words = 2,
0264 .offset_bits = 8,
0265 .size_bits = 24 }
0266 };
0267
0268 static const struct ib_field deth_table[] = {
0269 { STRUCT_FIELD(deth, qkey),
0270 .offset_words = 0,
0271 .offset_bits = 0,
0272 .size_bits = 32 },
0273 { RESERVED,
0274 .offset_words = 1,
0275 .offset_bits = 0,
0276 .size_bits = 8 },
0277 { STRUCT_FIELD(deth, source_qpn),
0278 .offset_words = 1,
0279 .offset_bits = 8,
0280 .size_bits = 24 }
0281 };
0282
0283 __sum16 ib_ud_ip4_csum(struct ib_ud_header *header)
0284 {
0285 struct iphdr iph;
0286
0287 iph.ihl = 5;
0288 iph.version = 4;
0289 iph.tos = header->ip4.tos;
0290 iph.tot_len = header->ip4.tot_len;
0291 iph.id = header->ip4.id;
0292 iph.frag_off = header->ip4.frag_off;
0293 iph.ttl = header->ip4.ttl;
0294 iph.protocol = header->ip4.protocol;
0295 iph.check = 0;
0296 iph.saddr = header->ip4.saddr;
0297 iph.daddr = header->ip4.daddr;
0298
0299 return ip_fast_csum((u8 *)&iph, iph.ihl);
0300 }
0301 EXPORT_SYMBOL(ib_ud_ip4_csum);
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315 int ib_ud_header_init(int payload_bytes,
0316 int lrh_present,
0317 int eth_present,
0318 int vlan_present,
0319 int grh_present,
0320 int ip_version,
0321 int udp_present,
0322 int immediate_present,
0323 struct ib_ud_header *header)
0324 {
0325 size_t udp_bytes = udp_present ? IB_UDP_BYTES : 0;
0326
0327 grh_present = grh_present && !ip_version;
0328 memset(header, 0, sizeof *header);
0329
0330
0331
0332
0333 if (udp_present && ip_version != 4 && ip_version != 6)
0334 return -EINVAL;
0335
0336 if (lrh_present) {
0337 u16 packet_length;
0338
0339 header->lrh.link_version = 0;
0340 header->lrh.link_next_header =
0341 grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
0342 packet_length = (IB_LRH_BYTES +
0343 IB_BTH_BYTES +
0344 IB_DETH_BYTES +
0345 (grh_present ? IB_GRH_BYTES : 0) +
0346 payload_bytes +
0347 4 +
0348 3) / 4;
0349 header->lrh.packet_length = cpu_to_be16(packet_length);
0350 }
0351
0352 if (vlan_present)
0353 header->eth.type = cpu_to_be16(ETH_P_8021Q);
0354
0355 if (ip_version == 6 || grh_present) {
0356 header->grh.ip_version = 6;
0357 header->grh.payload_length =
0358 cpu_to_be16((udp_bytes +
0359 IB_BTH_BYTES +
0360 IB_DETH_BYTES +
0361 payload_bytes +
0362 4 +
0363 3) & ~3);
0364 header->grh.next_header = udp_present ? IPPROTO_UDP : 0x1b;
0365 }
0366
0367 if (ip_version == 4) {
0368 header->ip4.ver = 4;
0369 header->ip4.hdr_len = 5;
0370 header->ip4.tot_len =
0371 cpu_to_be16(IB_IP4_BYTES +
0372 udp_bytes +
0373 IB_BTH_BYTES +
0374 IB_DETH_BYTES +
0375 payload_bytes +
0376 4);
0377 header->ip4.protocol = IPPROTO_UDP;
0378 }
0379 if (udp_present && ip_version)
0380 header->udp.length =
0381 cpu_to_be16(IB_UDP_BYTES +
0382 IB_BTH_BYTES +
0383 IB_DETH_BYTES +
0384 payload_bytes +
0385 4);
0386
0387 if (immediate_present)
0388 header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
0389 else
0390 header->bth.opcode = IB_OPCODE_UD_SEND_ONLY;
0391 header->bth.pad_count = (4 - payload_bytes) & 3;
0392 header->bth.transport_header_version = 0;
0393
0394 header->lrh_present = lrh_present;
0395 header->eth_present = eth_present;
0396 header->vlan_present = vlan_present;
0397 header->grh_present = grh_present || (ip_version == 6);
0398 header->ipv4_present = ip_version == 4;
0399 header->udp_present = udp_present;
0400 header->immediate_present = immediate_present;
0401 return 0;
0402 }
0403 EXPORT_SYMBOL(ib_ud_header_init);
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413 int ib_ud_header_pack(struct ib_ud_header *header,
0414 void *buf)
0415 {
0416 int len = 0;
0417
0418 if (header->lrh_present) {
0419 ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
0420 &header->lrh, buf + len);
0421 len += IB_LRH_BYTES;
0422 }
0423 if (header->eth_present) {
0424 ib_pack(eth_table, ARRAY_SIZE(eth_table),
0425 &header->eth, buf + len);
0426 len += IB_ETH_BYTES;
0427 }
0428 if (header->vlan_present) {
0429 ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
0430 &header->vlan, buf + len);
0431 len += IB_VLAN_BYTES;
0432 }
0433 if (header->grh_present) {
0434 ib_pack(grh_table, ARRAY_SIZE(grh_table),
0435 &header->grh, buf + len);
0436 len += IB_GRH_BYTES;
0437 }
0438 if (header->ipv4_present) {
0439 ib_pack(ip4_table, ARRAY_SIZE(ip4_table),
0440 &header->ip4, buf + len);
0441 len += IB_IP4_BYTES;
0442 }
0443 if (header->udp_present) {
0444 ib_pack(udp_table, ARRAY_SIZE(udp_table),
0445 &header->udp, buf + len);
0446 len += IB_UDP_BYTES;
0447 }
0448
0449 ib_pack(bth_table, ARRAY_SIZE(bth_table),
0450 &header->bth, buf + len);
0451 len += IB_BTH_BYTES;
0452
0453 ib_pack(deth_table, ARRAY_SIZE(deth_table),
0454 &header->deth, buf + len);
0455 len += IB_DETH_BYTES;
0456
0457 if (header->immediate_present) {
0458 memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data);
0459 len += sizeof header->immediate_data;
0460 }
0461
0462 return len;
0463 }
0464 EXPORT_SYMBOL(ib_ud_header_pack);
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474 int ib_ud_header_unpack(void *buf,
0475 struct ib_ud_header *header)
0476 {
0477 ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
0478 buf, &header->lrh);
0479 buf += IB_LRH_BYTES;
0480
0481 if (header->lrh.link_version != 0) {
0482 pr_warn("Invalid LRH.link_version %u\n",
0483 header->lrh.link_version);
0484 return -EINVAL;
0485 }
0486
0487 switch (header->lrh.link_next_header) {
0488 case IB_LNH_IBA_LOCAL:
0489 header->grh_present = 0;
0490 break;
0491
0492 case IB_LNH_IBA_GLOBAL:
0493 header->grh_present = 1;
0494 ib_unpack(grh_table, ARRAY_SIZE(grh_table),
0495 buf, &header->grh);
0496 buf += IB_GRH_BYTES;
0497
0498 if (header->grh.ip_version != 6) {
0499 pr_warn("Invalid GRH.ip_version %u\n",
0500 header->grh.ip_version);
0501 return -EINVAL;
0502 }
0503 if (header->grh.next_header != 0x1b) {
0504 pr_warn("Invalid GRH.next_header 0x%02x\n",
0505 header->grh.next_header);
0506 return -EINVAL;
0507 }
0508 break;
0509
0510 default:
0511 pr_warn("Invalid LRH.link_next_header %u\n",
0512 header->lrh.link_next_header);
0513 return -EINVAL;
0514 }
0515
0516 ib_unpack(bth_table, ARRAY_SIZE(bth_table),
0517 buf, &header->bth);
0518 buf += IB_BTH_BYTES;
0519
0520 switch (header->bth.opcode) {
0521 case IB_OPCODE_UD_SEND_ONLY:
0522 header->immediate_present = 0;
0523 break;
0524 case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
0525 header->immediate_present = 1;
0526 break;
0527 default:
0528 pr_warn("Invalid BTH.opcode 0x%02x\n", header->bth.opcode);
0529 return -EINVAL;
0530 }
0531
0532 if (header->bth.transport_header_version != 0) {
0533 pr_warn("Invalid BTH.transport_header_version %u\n",
0534 header->bth.transport_header_version);
0535 return -EINVAL;
0536 }
0537
0538 ib_unpack(deth_table, ARRAY_SIZE(deth_table),
0539 buf, &header->deth);
0540 buf += IB_DETH_BYTES;
0541
0542 if (header->immediate_present)
0543 memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
0544
0545 return 0;
0546 }
0547 EXPORT_SYMBOL(ib_ud_header_unpack);