2 * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <linux/tcp.h>
34 #include <linux/ipv6.h>
35 #include <net/route.h>
36 #include <net/ip6_route.h>
38 #include "libcxgb_cm.h"
41 cxgb_get_4tuple(struct cpl_pass_accept_req
*req
, enum chip_type type
,
42 int *iptype
, __u8
*local_ip
, __u8
*peer_ip
,
43 __be16
*local_port
, __be16
*peer_port
)
45 int eth_len
= (CHELSIO_CHIP_VERSION(type
) <= CHELSIO_T5
) ?
46 ETH_HDR_LEN_G(be32_to_cpu(req
->hdr_len
)) :
47 T6_ETH_HDR_LEN_G(be32_to_cpu(req
->hdr_len
));
48 int ip_len
= (CHELSIO_CHIP_VERSION(type
) <= CHELSIO_T5
) ?
49 IP_HDR_LEN_G(be32_to_cpu(req
->hdr_len
)) :
50 T6_IP_HDR_LEN_G(be32_to_cpu(req
->hdr_len
));
51 struct iphdr
*ip
= (struct iphdr
*)((u8
*)(req
+ 1) + eth_len
);
52 struct ipv6hdr
*ip6
= (struct ipv6hdr
*)((u8
*)(req
+ 1) + eth_len
);
53 struct tcphdr
*tcp
= (struct tcphdr
*)
54 ((u8
*)(req
+ 1) + eth_len
+ ip_len
);
56 if (ip
->version
== 4) {
57 pr_debug("%s saddr 0x%x daddr 0x%x sport %u dport %u\n",
58 __func__
, ntohl(ip
->saddr
), ntohl(ip
->daddr
),
59 ntohs(tcp
->source
), ntohs(tcp
->dest
));
61 memcpy(peer_ip
, &ip
->saddr
, 4);
62 memcpy(local_ip
, &ip
->daddr
, 4);
64 pr_debug("%s saddr %pI6 daddr %pI6 sport %u dport %u\n",
65 __func__
, ip6
->saddr
.s6_addr
, ip6
->daddr
.s6_addr
,
66 ntohs(tcp
->source
), ntohs(tcp
->dest
));
68 memcpy(peer_ip
, ip6
->saddr
.s6_addr
, 16);
69 memcpy(local_ip
, ip6
->daddr
.s6_addr
, 16);
71 *peer_port
= tcp
->source
;
72 *local_port
= tcp
->dest
;
74 EXPORT_SYMBOL(cxgb_get_4tuple
);
77 cxgb_our_interface(struct cxgb4_lld_info
*lldi
,
78 struct net_device
*(*get_real_dev
)(struct net_device
*),
79 struct net_device
*egress_dev
)
83 egress_dev
= get_real_dev(egress_dev
);
84 for (i
= 0; i
< lldi
->nports
; i
++)
85 if (lldi
->ports
[i
] == egress_dev
)
91 cxgb_find_route(struct cxgb4_lld_info
*lldi
,
92 struct net_device
*(*get_real_dev
)(struct net_device
*),
93 __be32 local_ip
, __be32 peer_ip
, __be16 local_port
,
94 __be16 peer_port
, u8 tos
)
100 rt
= ip_route_output_ports(&init_net
, &fl4
, NULL
, peer_ip
, local_ip
,
101 peer_port
, local_port
, IPPROTO_TCP
,
105 n
= dst_neigh_lookup(&rt
->dst
, &peer_ip
);
108 if (!cxgb_our_interface(lldi
, get_real_dev
, n
->dev
) &&
109 !(n
->dev
->flags
& IFF_LOOPBACK
)) {
111 dst_release(&rt
->dst
);
117 EXPORT_SYMBOL(cxgb_find_route
);
120 cxgb_find_route6(struct cxgb4_lld_info
*lldi
,
121 struct net_device
*(*get_real_dev
)(struct net_device
*),
122 __u8
*local_ip
, __u8
*peer_ip
, __be16 local_port
,
123 __be16 peer_port
, u8 tos
, __u32 sin6_scope_id
)
125 struct dst_entry
*dst
= NULL
;
127 if (IS_ENABLED(CONFIG_IPV6
)) {
130 memset(&fl6
, 0, sizeof(fl6
));
131 memcpy(&fl6
.daddr
, peer_ip
, 16);
132 memcpy(&fl6
.saddr
, local_ip
, 16);
133 if (ipv6_addr_type(&fl6
.daddr
) & IPV6_ADDR_LINKLOCAL
)
134 fl6
.flowi6_oif
= sin6_scope_id
;
135 dst
= ip6_route_output(&init_net
, NULL
, &fl6
);
138 if (!cxgb_our_interface(lldi
, get_real_dev
,
139 ip6_dst_idev(dst
)->dev
) &&
140 !(ip6_dst_idev(dst
)->dev
->flags
& IFF_LOOPBACK
)) {
149 EXPORT_SYMBOL(cxgb_find_route6
);