1
2
3
4
5
6#include <linux/types.h>
7#include <asm/byteorder.h>
8#include <asm/param.h>
9#include <linux/delay.h>
10#include <linux/pci.h>
11#include <linux/dma-mapping.h>
12#include <linux/etherdevice.h>
13#include <linux/kernel.h>
14#include <linux/stddef.h>
15#include <linux/errno.h>
16
17#include <net/tcp.h>
18
19#include <linux/qed/qed_nvmetcp_ip_services_if.h>
20
21#define QED_IP_RESOL_TIMEOUT 4
22
23int qed_route_ipv4(struct sockaddr_storage *local_addr,
24 struct sockaddr_storage *remote_addr,
25 struct sockaddr *hardware_address,
26 struct net_device **ndev)
27{
28 struct neighbour *neigh = NULL;
29 __be32 *loc_ip, *rem_ip;
30 struct rtable *rt;
31 int rc = -ENXIO;
32 int retry;
33
34 loc_ip = &((struct sockaddr_in *)local_addr)->sin_addr.s_addr;
35 rem_ip = &((struct sockaddr_in *)remote_addr)->sin_addr.s_addr;
36 *ndev = NULL;
37 rt = ip_route_output(&init_net, *rem_ip, *loc_ip, 0, 0);
38 if (IS_ERR(rt)) {
39 pr_err("lookup route failed\n");
40 rc = PTR_ERR(rt);
41 goto return_err;
42 }
43
44 neigh = dst_neigh_lookup(&rt->dst, rem_ip);
45 if (!neigh) {
46 rc = -ENOMEM;
47 ip_rt_put(rt);
48 goto return_err;
49 }
50
51 *ndev = rt->dst.dev;
52 ip_rt_put(rt);
53
54
55 if (!(neigh->nud_state & NUD_VALID))
56 neigh_event_send(neigh, NULL);
57
58
59 retry = QED_IP_RESOL_TIMEOUT;
60 while (!(neigh->nud_state & NUD_VALID) && retry > 0) {
61 msleep(1000);
62 retry--;
63 }
64
65 if (neigh->nud_state & NUD_VALID) {
66
67 neigh_ha_snapshot(hardware_address->sa_data, neigh, *ndev);
68 hardware_address->sa_family = (*ndev)->type;
69 rc = 0;
70 }
71
72 neigh_release(neigh);
73 if (!(*loc_ip)) {
74 *loc_ip = inet_select_addr(*ndev, *rem_ip, RT_SCOPE_UNIVERSE);
75 local_addr->ss_family = AF_INET;
76 }
77
78return_err:
79
80 return rc;
81}
82EXPORT_SYMBOL(qed_route_ipv4);
83
84int qed_route_ipv6(struct sockaddr_storage *local_addr,
85 struct sockaddr_storage *remote_addr,
86 struct sockaddr *hardware_address,
87 struct net_device **ndev)
88{
89 struct neighbour *neigh = NULL;
90 struct dst_entry *dst;
91 struct flowi6 fl6;
92 int rc = -ENXIO;
93 int retry;
94
95 memset(&fl6, 0, sizeof(fl6));
96 fl6.saddr = ((struct sockaddr_in6 *)local_addr)->sin6_addr;
97 fl6.daddr = ((struct sockaddr_in6 *)remote_addr)->sin6_addr;
98 dst = ip6_route_output(&init_net, NULL, &fl6);
99 if (!dst || dst->error) {
100 if (dst) {
101 dst_release(dst);
102 pr_err("lookup route failed %d\n", dst->error);
103 }
104
105 goto out;
106 }
107
108 neigh = dst_neigh_lookup(dst, &fl6.daddr);
109 if (neigh) {
110 *ndev = ip6_dst_idev(dst)->dev;
111
112
113 if (!(neigh->nud_state & NUD_VALID))
114 neigh_event_send(neigh, NULL);
115
116
117 retry = QED_IP_RESOL_TIMEOUT;
118 while (!(neigh->nud_state & NUD_VALID) && retry > 0) {
119 msleep(1000);
120 retry--;
121 }
122
123 if (neigh->nud_state & NUD_VALID) {
124 neigh_ha_snapshot((u8 *)hardware_address->sa_data,
125 neigh, *ndev);
126 hardware_address->sa_family = (*ndev)->type;
127 rc = 0;
128 }
129
130 neigh_release(neigh);
131
132 if (ipv6_addr_any(&fl6.saddr)) {
133 if (ipv6_dev_get_saddr(dev_net(*ndev), *ndev,
134 &fl6.daddr, 0, &fl6.saddr)) {
135 pr_err("Unable to find source IP address\n");
136 goto out;
137 }
138
139 local_addr->ss_family = AF_INET6;
140 ((struct sockaddr_in6 *)local_addr)->sin6_addr =
141 fl6.saddr;
142 }
143 }
144
145 dst_release(dst);
146
147out:
148
149 return rc;
150}
151EXPORT_SYMBOL(qed_route_ipv6);
152
153void qed_vlan_get_ndev(struct net_device **ndev, u16 *vlan_id)
154{
155 if (is_vlan_dev(*ndev)) {
156 *vlan_id = vlan_dev_vlan_id(*ndev);
157 *ndev = vlan_dev_real_dev(*ndev);
158 }
159}
160EXPORT_SYMBOL(qed_vlan_get_ndev);
161
162struct pci_dev *qed_validate_ndev(struct net_device *ndev)
163{
164 struct pci_dev *pdev = NULL;
165 struct net_device *upper;
166
167 for_each_pci_dev(pdev) {
168 if (pdev && pdev->driver &&
169 !strcmp(pdev->driver->name, "qede")) {
170 upper = pci_get_drvdata(pdev);
171 if (upper->ifindex == ndev->ifindex)
172 return pdev;
173 }
174 }
175
176 return NULL;
177}
178EXPORT_SYMBOL(qed_validate_ndev);
179
180__be16 qed_get_in_port(struct sockaddr_storage *sa)
181{
182 return sa->ss_family == AF_INET
183 ? ((struct sockaddr_in *)sa)->sin_port
184 : ((struct sockaddr_in6 *)sa)->sin6_port;
185}
186EXPORT_SYMBOL(qed_get_in_port);
187
188int qed_fetch_tcp_port(struct sockaddr_storage local_ip_addr,
189 struct socket **sock, u16 *port)
190{
191 struct sockaddr_storage sa;
192 int rc = 0;
193
194 rc = sock_create(local_ip_addr.ss_family, SOCK_STREAM, IPPROTO_TCP,
195 sock);
196 if (rc) {
197 pr_warn("failed to create socket: %d\n", rc);
198 goto err;
199 }
200
201 (*sock)->sk->sk_allocation = GFP_KERNEL;
202 sk_set_memalloc((*sock)->sk);
203
204 rc = kernel_bind(*sock, (struct sockaddr *)&local_ip_addr,
205 sizeof(local_ip_addr));
206
207 if (rc) {
208 pr_warn("failed to bind socket: %d\n", rc);
209 goto err_sock;
210 }
211
212 rc = kernel_getsockname(*sock, (struct sockaddr *)&sa);
213 if (rc < 0) {
214 pr_warn("getsockname() failed: %d\n", rc);
215 goto err_sock;
216 }
217
218 *port = ntohs(qed_get_in_port(&sa));
219
220 return 0;
221
222err_sock:
223 sock_release(*sock);
224 sock = NULL;
225err:
226
227 return rc;
228}
229EXPORT_SYMBOL(qed_fetch_tcp_port);
230
231void qed_return_tcp_port(struct socket *sock)
232{
233 if (sock && sock->sk) {
234 tcp_set_state(sock->sk, TCP_CLOSE);
235 sock_release(sock);
236 }
237}
238EXPORT_SYMBOL(qed_return_tcp_port);
239