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/inet_ecn.h>
36 #include <net/route.h>
37 #include <net/ip6_route.h>
39 #include "libcxgb_cm.h"
42 cxgb_get_4tuple(struct cpl_pass_accept_req
*req
, enum chip_type type
,
43 int *iptype
, __u8
*local_ip
, __u8
*peer_ip
,
44 __be16
*local_port
, __be16
*peer_port
)
46 int eth_len
= (CHELSIO_CHIP_VERSION(type
) <= CHELSIO_T5
) ?
47 ETH_HDR_LEN_G(be32_to_cpu(req
->hdr_len
)) :
48 T6_ETH_HDR_LEN_G(be32_to_cpu(req
->hdr_len
));
49 int ip_len
= (CHELSIO_CHIP_VERSION(type
) <= CHELSIO_T5
) ?
50 IP_HDR_LEN_G(be32_to_cpu(req
->hdr_len
)) :
51 T6_IP_HDR_LEN_G(be32_to_cpu(req
->hdr_len
));
52 struct iphdr
*ip
= (struct iphdr
*)((u8
*)(req
+ 1) + eth_len
);
53 struct ipv6hdr
*ip6
= (struct ipv6hdr
*)((u8
*)(req
+ 1) + eth_len
);
54 struct tcphdr
*tcp
= (struct tcphdr
*)
55 ((u8
*)(req
+ 1) + eth_len
+ ip_len
);
57 if (ip
->version
== 4) {
58 pr_debug("%s saddr 0x%x daddr 0x%x sport %u dport %u\n",
59 __func__
, ntohl(ip
->saddr
), ntohl(ip
->daddr
),
60 ntohs(tcp
->source
), ntohs(tcp
->dest
));
62 memcpy(peer_ip
, &ip
->saddr
, 4);
63 memcpy(local_ip
, &ip
->daddr
, 4);
65 pr_debug("%s saddr %pI6 daddr %pI6 sport %u dport %u\n",
66 __func__
, ip6
->saddr
.s6_addr
, ip6
->daddr
.s6_addr
,
67 ntohs(tcp
->source
), ntohs(tcp
->dest
));
69 memcpy(peer_ip
, ip6
->saddr
.s6_addr
, 16);
70 memcpy(local_ip
, ip6
->daddr
.s6_addr
, 16);
72 *peer_port
= tcp
->source
;
73 *local_port
= tcp
->dest
;
75 EXPORT_SYMBOL(cxgb_get_4tuple
);
78 cxgb_our_interface(struct cxgb4_lld_info
*lldi
,
79 struct net_device
*(*get_real_dev
)(struct net_device
*),
80 struct net_device
*egress_dev
)
84 egress_dev
= get_real_dev(egress_dev
);
85 for (i
= 0; i
< lldi
->nports
; i
++)
86 if (lldi
->ports
[i
] == egress_dev
)
92 cxgb_find_route(struct cxgb4_lld_info
*lldi
,
93 struct net_device
*(*get_real_dev
)(struct net_device
*),
94 __be32 local_ip
, __be32 peer_ip
, __be16 local_port
,
95 __be16 peer_port
, u8 tos
)
101 rt
= ip_route_output_ports(&init_net
, &fl4
, NULL
, peer_ip
, local_ip
,
102 peer_port
, local_port
, IPPROTO_TCP
,
103 tos
& ~INET_ECN_MASK
, 0);
106 n
= dst_neigh_lookup(&rt
->dst
, &peer_ip
);
109 if (!cxgb_our_interface(lldi
, get_real_dev
, n
->dev
) &&
110 !(n
->dev
->flags
& IFF_LOOPBACK
)) {
112 dst_release(&rt
->dst
);
118 EXPORT_SYMBOL(cxgb_find_route
);
121 cxgb_find_route6(struct cxgb4_lld_info
*lldi
,
122 struct net_device
*(*get_real_dev
)(struct net_device
*),
123 __u8
*local_ip
, __u8
*peer_ip
, __be16 local_port
,
124 __be16 peer_port
, u8 tos
, __u32 sin6_scope_id
)
126 struct dst_entry
*dst
= NULL
;
128 if (IS_ENABLED(CONFIG_IPV6
)) {
131 memset(&fl6
, 0, sizeof(fl6
));
132 memcpy(&fl6
.daddr
, peer_ip
, 16);
133 memcpy(&fl6
.saddr
, local_ip
, 16);
134 if (ipv6_addr_type(&fl6
.daddr
) & IPV6_ADDR_LINKLOCAL
)
135 fl6
.flowi6_oif
= sin6_scope_id
;
136 dst
= ip6_route_output(&init_net
, NULL
, &fl6
);
138 (!cxgb_our_interface(lldi
, get_real_dev
,
139 ip6_dst_idev(dst
)->dev
) &&
140 !(ip6_dst_idev(dst
)->dev
->flags
& IFF_LOOPBACK
))) {
148 EXPORT_SYMBOL(cxgb_find_route6
);