18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/tcp.h> 348c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 358c2ecf20Sopenharmony_ci#include <net/inet_ecn.h> 368c2ecf20Sopenharmony_ci#include <net/route.h> 378c2ecf20Sopenharmony_ci#include <net/ip6_route.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "libcxgb_cm.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_civoid 428c2ecf20Sopenharmony_cicxgb_get_4tuple(struct cpl_pass_accept_req *req, enum chip_type type, 438c2ecf20Sopenharmony_ci int *iptype, __u8 *local_ip, __u8 *peer_ip, 448c2ecf20Sopenharmony_ci __be16 *local_port, __be16 *peer_port) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci int eth_len = (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) ? 478c2ecf20Sopenharmony_ci ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len)) : 488c2ecf20Sopenharmony_ci T6_ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len)); 498c2ecf20Sopenharmony_ci int ip_len = (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) ? 508c2ecf20Sopenharmony_ci IP_HDR_LEN_G(be32_to_cpu(req->hdr_len)) : 518c2ecf20Sopenharmony_ci T6_IP_HDR_LEN_G(be32_to_cpu(req->hdr_len)); 528c2ecf20Sopenharmony_ci struct iphdr *ip = (struct iphdr *)((u8 *)(req + 1) + eth_len); 538c2ecf20Sopenharmony_ci struct ipv6hdr *ip6 = (struct ipv6hdr *)((u8 *)(req + 1) + eth_len); 548c2ecf20Sopenharmony_ci struct tcphdr *tcp = (struct tcphdr *) 558c2ecf20Sopenharmony_ci ((u8 *)(req + 1) + eth_len + ip_len); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (ip->version == 4) { 588c2ecf20Sopenharmony_ci pr_debug("%s saddr 0x%x daddr 0x%x sport %u dport %u\n", 598c2ecf20Sopenharmony_ci __func__, ntohl(ip->saddr), ntohl(ip->daddr), 608c2ecf20Sopenharmony_ci ntohs(tcp->source), ntohs(tcp->dest)); 618c2ecf20Sopenharmony_ci *iptype = 4; 628c2ecf20Sopenharmony_ci memcpy(peer_ip, &ip->saddr, 4); 638c2ecf20Sopenharmony_ci memcpy(local_ip, &ip->daddr, 4); 648c2ecf20Sopenharmony_ci } else { 658c2ecf20Sopenharmony_ci pr_debug("%s saddr %pI6 daddr %pI6 sport %u dport %u\n", 668c2ecf20Sopenharmony_ci __func__, ip6->saddr.s6_addr, ip6->daddr.s6_addr, 678c2ecf20Sopenharmony_ci ntohs(tcp->source), ntohs(tcp->dest)); 688c2ecf20Sopenharmony_ci *iptype = 6; 698c2ecf20Sopenharmony_ci memcpy(peer_ip, ip6->saddr.s6_addr, 16); 708c2ecf20Sopenharmony_ci memcpy(local_ip, ip6->daddr.s6_addr, 16); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci *peer_port = tcp->source; 738c2ecf20Sopenharmony_ci *local_port = tcp->dest; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb_get_4tuple); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic bool 788c2ecf20Sopenharmony_cicxgb_our_interface(struct cxgb4_lld_info *lldi, 798c2ecf20Sopenharmony_ci struct net_device *(*get_real_dev)(struct net_device *), 808c2ecf20Sopenharmony_ci struct net_device *egress_dev) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci int i; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci egress_dev = get_real_dev(egress_dev); 858c2ecf20Sopenharmony_ci for (i = 0; i < lldi->nports; i++) 868c2ecf20Sopenharmony_ci if (lldi->ports[i] == egress_dev) 878c2ecf20Sopenharmony_ci return true; 888c2ecf20Sopenharmony_ci return false; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistruct dst_entry * 928c2ecf20Sopenharmony_cicxgb_find_route(struct cxgb4_lld_info *lldi, 938c2ecf20Sopenharmony_ci struct net_device *(*get_real_dev)(struct net_device *), 948c2ecf20Sopenharmony_ci __be32 local_ip, __be32 peer_ip, __be16 local_port, 958c2ecf20Sopenharmony_ci __be16 peer_port, u8 tos) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct rtable *rt; 988c2ecf20Sopenharmony_ci struct flowi4 fl4; 998c2ecf20Sopenharmony_ci struct neighbour *n; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip, 1028c2ecf20Sopenharmony_ci peer_port, local_port, IPPROTO_TCP, 1038c2ecf20Sopenharmony_ci tos & ~INET_ECN_MASK, 0); 1048c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 1058c2ecf20Sopenharmony_ci return NULL; 1068c2ecf20Sopenharmony_ci n = dst_neigh_lookup(&rt->dst, &peer_ip); 1078c2ecf20Sopenharmony_ci if (!n) 1088c2ecf20Sopenharmony_ci return NULL; 1098c2ecf20Sopenharmony_ci if (!cxgb_our_interface(lldi, get_real_dev, n->dev) && 1108c2ecf20Sopenharmony_ci !(n->dev->flags & IFF_LOOPBACK)) { 1118c2ecf20Sopenharmony_ci neigh_release(n); 1128c2ecf20Sopenharmony_ci dst_release(&rt->dst); 1138c2ecf20Sopenharmony_ci return NULL; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci neigh_release(n); 1168c2ecf20Sopenharmony_ci return &rt->dst; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb_find_route); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistruct dst_entry * 1218c2ecf20Sopenharmony_cicxgb_find_route6(struct cxgb4_lld_info *lldi, 1228c2ecf20Sopenharmony_ci struct net_device *(*get_real_dev)(struct net_device *), 1238c2ecf20Sopenharmony_ci __u8 *local_ip, __u8 *peer_ip, __be16 local_port, 1248c2ecf20Sopenharmony_ci __be16 peer_port, u8 tos, __u32 sin6_scope_id) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct dst_entry *dst = NULL; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_IPV6)) { 1298c2ecf20Sopenharmony_ci struct flowi6 fl6; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci memset(&fl6, 0, sizeof(fl6)); 1328c2ecf20Sopenharmony_ci memcpy(&fl6.daddr, peer_ip, 16); 1338c2ecf20Sopenharmony_ci memcpy(&fl6.saddr, local_ip, 16); 1348c2ecf20Sopenharmony_ci if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL) 1358c2ecf20Sopenharmony_ci fl6.flowi6_oif = sin6_scope_id; 1368c2ecf20Sopenharmony_ci dst = ip6_route_output(&init_net, NULL, &fl6); 1378c2ecf20Sopenharmony_ci if (dst->error || 1388c2ecf20Sopenharmony_ci (!cxgb_our_interface(lldi, get_real_dev, 1398c2ecf20Sopenharmony_ci ip6_dst_idev(dst)->dev) && 1408c2ecf20Sopenharmony_ci !(ip6_dst_idev(dst)->dev->flags & IFF_LOOPBACK))) { 1418c2ecf20Sopenharmony_ci dst_release(dst); 1428c2ecf20Sopenharmony_ci return NULL; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return dst; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb_find_route6); 149