162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/tcp.h> 3462306a36Sopenharmony_ci#include <linux/ipv6.h> 3562306a36Sopenharmony_ci#include <net/inet_ecn.h> 3662306a36Sopenharmony_ci#include <net/route.h> 3762306a36Sopenharmony_ci#include <net/ip6_route.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "libcxgb_cm.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_civoid 4262306a36Sopenharmony_cicxgb_get_4tuple(struct cpl_pass_accept_req *req, enum chip_type type, 4362306a36Sopenharmony_ci int *iptype, __u8 *local_ip, __u8 *peer_ip, 4462306a36Sopenharmony_ci __be16 *local_port, __be16 *peer_port) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci int eth_len = (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) ? 4762306a36Sopenharmony_ci ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len)) : 4862306a36Sopenharmony_ci T6_ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len)); 4962306a36Sopenharmony_ci int ip_len = (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) ? 5062306a36Sopenharmony_ci IP_HDR_LEN_G(be32_to_cpu(req->hdr_len)) : 5162306a36Sopenharmony_ci T6_IP_HDR_LEN_G(be32_to_cpu(req->hdr_len)); 5262306a36Sopenharmony_ci struct iphdr *ip = (struct iphdr *)((u8 *)(req + 1) + eth_len); 5362306a36Sopenharmony_ci struct ipv6hdr *ip6 = (struct ipv6hdr *)((u8 *)(req + 1) + eth_len); 5462306a36Sopenharmony_ci struct tcphdr *tcp = (struct tcphdr *) 5562306a36Sopenharmony_ci ((u8 *)(req + 1) + eth_len + ip_len); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (ip->version == 4) { 5862306a36Sopenharmony_ci pr_debug("%s saddr 0x%x daddr 0x%x sport %u dport %u\n", 5962306a36Sopenharmony_ci __func__, ntohl(ip->saddr), ntohl(ip->daddr), 6062306a36Sopenharmony_ci ntohs(tcp->source), ntohs(tcp->dest)); 6162306a36Sopenharmony_ci *iptype = 4; 6262306a36Sopenharmony_ci memcpy(peer_ip, &ip->saddr, 4); 6362306a36Sopenharmony_ci memcpy(local_ip, &ip->daddr, 4); 6462306a36Sopenharmony_ci } else { 6562306a36Sopenharmony_ci pr_debug("%s saddr %pI6 daddr %pI6 sport %u dport %u\n", 6662306a36Sopenharmony_ci __func__, ip6->saddr.s6_addr, ip6->daddr.s6_addr, 6762306a36Sopenharmony_ci ntohs(tcp->source), ntohs(tcp->dest)); 6862306a36Sopenharmony_ci *iptype = 6; 6962306a36Sopenharmony_ci memcpy(peer_ip, ip6->saddr.s6_addr, 16); 7062306a36Sopenharmony_ci memcpy(local_ip, ip6->daddr.s6_addr, 16); 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci *peer_port = tcp->source; 7362306a36Sopenharmony_ci *local_port = tcp->dest; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb_get_4tuple); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic bool 7862306a36Sopenharmony_cicxgb_our_interface(struct cxgb4_lld_info *lldi, 7962306a36Sopenharmony_ci struct net_device *(*get_real_dev)(struct net_device *), 8062306a36Sopenharmony_ci struct net_device *egress_dev) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int i; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci egress_dev = get_real_dev(egress_dev); 8562306a36Sopenharmony_ci for (i = 0; i < lldi->nports; i++) 8662306a36Sopenharmony_ci if (lldi->ports[i] == egress_dev) 8762306a36Sopenharmony_ci return true; 8862306a36Sopenharmony_ci return false; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistruct dst_entry * 9262306a36Sopenharmony_cicxgb_find_route(struct cxgb4_lld_info *lldi, 9362306a36Sopenharmony_ci struct net_device *(*get_real_dev)(struct net_device *), 9462306a36Sopenharmony_ci __be32 local_ip, __be32 peer_ip, __be16 local_port, 9562306a36Sopenharmony_ci __be16 peer_port, u8 tos) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct rtable *rt; 9862306a36Sopenharmony_ci struct flowi4 fl4; 9962306a36Sopenharmony_ci struct neighbour *n; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip, 10262306a36Sopenharmony_ci peer_port, local_port, IPPROTO_TCP, 10362306a36Sopenharmony_ci tos & ~INET_ECN_MASK, 0); 10462306a36Sopenharmony_ci if (IS_ERR(rt)) 10562306a36Sopenharmony_ci return NULL; 10662306a36Sopenharmony_ci n = dst_neigh_lookup(&rt->dst, &peer_ip); 10762306a36Sopenharmony_ci if (!n) 10862306a36Sopenharmony_ci return NULL; 10962306a36Sopenharmony_ci if (!cxgb_our_interface(lldi, get_real_dev, n->dev) && 11062306a36Sopenharmony_ci !(n->dev->flags & IFF_LOOPBACK)) { 11162306a36Sopenharmony_ci neigh_release(n); 11262306a36Sopenharmony_ci dst_release(&rt->dst); 11362306a36Sopenharmony_ci return NULL; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci neigh_release(n); 11662306a36Sopenharmony_ci return &rt->dst; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb_find_route); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistruct dst_entry * 12162306a36Sopenharmony_cicxgb_find_route6(struct cxgb4_lld_info *lldi, 12262306a36Sopenharmony_ci struct net_device *(*get_real_dev)(struct net_device *), 12362306a36Sopenharmony_ci __u8 *local_ip, __u8 *peer_ip, __be16 local_port, 12462306a36Sopenharmony_ci __be16 peer_port, u8 tos, __u32 sin6_scope_id) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct dst_entry *dst = NULL; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_IPV6)) { 12962306a36Sopenharmony_ci struct flowi6 fl6; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci memset(&fl6, 0, sizeof(fl6)); 13262306a36Sopenharmony_ci memcpy(&fl6.daddr, peer_ip, 16); 13362306a36Sopenharmony_ci memcpy(&fl6.saddr, local_ip, 16); 13462306a36Sopenharmony_ci if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL) 13562306a36Sopenharmony_ci fl6.flowi6_oif = sin6_scope_id; 13662306a36Sopenharmony_ci dst = ip6_route_output(&init_net, NULL, &fl6); 13762306a36Sopenharmony_ci if (dst->error || 13862306a36Sopenharmony_ci (!cxgb_our_interface(lldi, get_real_dev, 13962306a36Sopenharmony_ci ip6_dst_idev(dst)->dev) && 14062306a36Sopenharmony_ci !(ip6_dst_idev(dst)->dev->flags & IFF_LOOPBACK))) { 14162306a36Sopenharmony_ci dst_release(dst); 14262306a36Sopenharmony_ci return NULL; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return dst; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb_find_route6); 149