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 #include <linux/tcp.h>
0034 #include <linux/ipv6.h>
0035 #include <net/inet_ecn.h>
0036 #include <net/route.h>
0037 #include <net/ip6_route.h>
0038
0039 #include "libcxgb_cm.h"
0040
0041 void
0042 cxgb_get_4tuple(struct cpl_pass_accept_req *req, enum chip_type type,
0043 int *iptype, __u8 *local_ip, __u8 *peer_ip,
0044 __be16 *local_port, __be16 *peer_port)
0045 {
0046 int eth_len = (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) ?
0047 ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len)) :
0048 T6_ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len));
0049 int ip_len = (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) ?
0050 IP_HDR_LEN_G(be32_to_cpu(req->hdr_len)) :
0051 T6_IP_HDR_LEN_G(be32_to_cpu(req->hdr_len));
0052 struct iphdr *ip = (struct iphdr *)((u8 *)(req + 1) + eth_len);
0053 struct ipv6hdr *ip6 = (struct ipv6hdr *)((u8 *)(req + 1) + eth_len);
0054 struct tcphdr *tcp = (struct tcphdr *)
0055 ((u8 *)(req + 1) + eth_len + ip_len);
0056
0057 if (ip->version == 4) {
0058 pr_debug("%s saddr 0x%x daddr 0x%x sport %u dport %u\n",
0059 __func__, ntohl(ip->saddr), ntohl(ip->daddr),
0060 ntohs(tcp->source), ntohs(tcp->dest));
0061 *iptype = 4;
0062 memcpy(peer_ip, &ip->saddr, 4);
0063 memcpy(local_ip, &ip->daddr, 4);
0064 } else {
0065 pr_debug("%s saddr %pI6 daddr %pI6 sport %u dport %u\n",
0066 __func__, ip6->saddr.s6_addr, ip6->daddr.s6_addr,
0067 ntohs(tcp->source), ntohs(tcp->dest));
0068 *iptype = 6;
0069 memcpy(peer_ip, ip6->saddr.s6_addr, 16);
0070 memcpy(local_ip, ip6->daddr.s6_addr, 16);
0071 }
0072 *peer_port = tcp->source;
0073 *local_port = tcp->dest;
0074 }
0075 EXPORT_SYMBOL(cxgb_get_4tuple);
0076
0077 static bool
0078 cxgb_our_interface(struct cxgb4_lld_info *lldi,
0079 struct net_device *(*get_real_dev)(struct net_device *),
0080 struct net_device *egress_dev)
0081 {
0082 int i;
0083
0084 egress_dev = get_real_dev(egress_dev);
0085 for (i = 0; i < lldi->nports; i++)
0086 if (lldi->ports[i] == egress_dev)
0087 return true;
0088 return false;
0089 }
0090
0091 struct dst_entry *
0092 cxgb_find_route(struct cxgb4_lld_info *lldi,
0093 struct net_device *(*get_real_dev)(struct net_device *),
0094 __be32 local_ip, __be32 peer_ip, __be16 local_port,
0095 __be16 peer_port, u8 tos)
0096 {
0097 struct rtable *rt;
0098 struct flowi4 fl4;
0099 struct neighbour *n;
0100
0101 rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip,
0102 peer_port, local_port, IPPROTO_TCP,
0103 tos & ~INET_ECN_MASK, 0);
0104 if (IS_ERR(rt))
0105 return NULL;
0106 n = dst_neigh_lookup(&rt->dst, &peer_ip);
0107 if (!n)
0108 return NULL;
0109 if (!cxgb_our_interface(lldi, get_real_dev, n->dev) &&
0110 !(n->dev->flags & IFF_LOOPBACK)) {
0111 neigh_release(n);
0112 dst_release(&rt->dst);
0113 return NULL;
0114 }
0115 neigh_release(n);
0116 return &rt->dst;
0117 }
0118 EXPORT_SYMBOL(cxgb_find_route);
0119
0120 struct dst_entry *
0121 cxgb_find_route6(struct cxgb4_lld_info *lldi,
0122 struct net_device *(*get_real_dev)(struct net_device *),
0123 __u8 *local_ip, __u8 *peer_ip, __be16 local_port,
0124 __be16 peer_port, u8 tos, __u32 sin6_scope_id)
0125 {
0126 struct dst_entry *dst = NULL;
0127
0128 if (IS_ENABLED(CONFIG_IPV6)) {
0129 struct flowi6 fl6;
0130
0131 memset(&fl6, 0, sizeof(fl6));
0132 memcpy(&fl6.daddr, peer_ip, 16);
0133 memcpy(&fl6.saddr, local_ip, 16);
0134 if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL)
0135 fl6.flowi6_oif = sin6_scope_id;
0136 dst = ip6_route_output(&init_net, NULL, &fl6);
0137 if (dst->error ||
0138 (!cxgb_our_interface(lldi, get_real_dev,
0139 ip6_dst_idev(dst)->dev) &&
0140 !(ip6_dst_idev(dst)->dev->flags & IFF_LOOPBACK))) {
0141 dst_release(dst);
0142 return NULL;
0143 }
0144 }
0145
0146 return dst;
0147 }
0148 EXPORT_SYMBOL(cxgb_find_route6);