blob: b26f7d7a2ca0d41c787a4e9932583ee3d3a32107 [file] [log] [blame]
Greg Kroah-Hartmanab9953f2017-11-14 18:38:04 +01001// SPDX-License-Identifier: GPL-2.0
Frank Blaschka4a71df52008-02-15 09:19:42 +01002/*
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02003 * Copyright IBM Corp. 2007, 2009
Frank Blaschka4a71df52008-02-15 09:19:42 +01004 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
5 * Frank Pavlic <fpavlic@de.ibm.com>,
6 * Thomas Spatzier <tspat@de.ibm.com>,
7 * Frank Blaschka <frank.blaschka@de.ibm.com>
8 */
9
Frank Blaschka74eacdb2008-12-25 13:39:49 +010010#define KMSG_COMPONENT "qeth"
11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12
Frank Blaschka4a71df52008-02-15 09:19:42 +010013#include <linux/module.h>
14#include <linux/moduleparam.h>
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +000015#include <linux/bitops.h>
Frank Blaschka4a71df52008-02-15 09:19:42 +010016#include <linux/string.h>
17#include <linux/errno.h>
18#include <linux/kernel.h>
19#include <linux/etherdevice.h>
Frank Blaschka4a71df52008-02-15 09:19:42 +010020#include <linux/ip.h>
Julian Wiedmann1f979122017-12-20 20:11:04 +010021#include <linux/in.h>
Frank Blaschka64ef8952009-03-24 20:57:16 +000022#include <linux/ipv6.h>
Frank Blaschka4a71df52008-02-15 09:19:42 +010023#include <linux/inetdevice.h>
24#include <linux/igmp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Julian Wiedmann910a0a82017-12-20 20:11:07 +010026#include <linux/if_ether.h>
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +000027#include <linux/if_vlan.h>
Julian Wiedmann910a0a82017-12-20 20:11:07 +010028#include <linux/skbuff.h>
Frank Blaschka4a71df52008-02-15 09:19:42 +010029
30#include <net/ip.h>
31#include <net/arp.h>
David Miller87e75972012-02-01 10:49:17 +000032#include <net/route.h>
Julian Wiedmann1f979122017-12-20 20:11:04 +010033#include <net/ipv6.h>
Julian Wiedmann910a0a82017-12-20 20:11:07 +010034#include <net/ip6_route.h>
David Miller87e75972012-02-01 10:49:17 +000035#include <net/ip6_fib.h>
Frank Blaschkab3332932011-08-08 01:33:59 +000036#include <net/iucv/af_iucv.h>
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +020037#include <linux/hashtable.h>
Frank Blaschka4a71df52008-02-15 09:19:42 +010038
Frank Blaschka4a71df52008-02-15 09:19:42 +010039#include "qeth_l3.h"
Frank Blaschka4a71df52008-02-15 09:19:42 +010040
Einar Lueckd0ddf30f2010-12-08 02:57:58 +000041
Frank Blaschka4a71df52008-02-15 09:19:42 +010042static int qeth_l3_set_offline(struct ccwgroup_device *);
Frank Blaschka4a71df52008-02-15 09:19:42 +010043static int qeth_l3_stop(struct net_device *);
Julian Wiedmann00c163f2017-12-20 20:11:02 +010044static void qeth_l3_set_rx_mode(struct net_device *dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +010045static int qeth_l3_register_addr_entry(struct qeth_card *,
46 struct qeth_ipaddr *);
47static int qeth_l3_deregister_addr_entry(struct qeth_card *,
48 struct qeth_ipaddr *);
Frank Blaschka4a71df52008-02-15 09:19:42 +010049
Thomas Richter56530d62014-10-22 12:18:04 +020050static void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf)
Frank Blaschka4a71df52008-02-15 09:19:42 +010051{
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +020052 sprintf(buf, "%pI4", addr);
Frank Blaschka4a71df52008-02-15 09:19:42 +010053}
54
Thomas Richter56530d62014-10-22 12:18:04 +020055static void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
Frank Blaschka4a71df52008-02-15 09:19:42 +010056{
Joe Perches963a9fd2010-09-07 21:14:40 +000057 sprintf(buf, "%pI6", addr);
Frank Blaschka4a71df52008-02-15 09:19:42 +010058}
59
Frank Blaschka4a71df52008-02-15 09:19:42 +010060void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
61 char *buf)
62{
63 if (proto == QETH_PROT_IPV4)
64 qeth_l3_ipaddr4_to_string(addr, buf);
65 else if (proto == QETH_PROT_IPV6)
66 qeth_l3_ipaddr6_to_string(addr, buf);
67}
68
Julian Wiedmann1617dae2018-03-09 18:13:02 +010069static struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions prot)
Julian Wiedmannd66b1c02018-03-09 18:13:00 +010070{
71 struct qeth_ipaddr *addr = kmalloc(sizeof(*addr), GFP_ATOMIC);
72
73 if (addr)
74 qeth_l3_init_ipaddr(addr, QETH_IP_TYPE_NORMAL, prot);
75 return addr;
76}
77
Julian Wiedmannc5c48c52018-02-27 18:58:16 +010078static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card,
79 struct qeth_ipaddr *query)
80{
81 u64 key = qeth_l3_ipaddr_hash(query);
82 struct qeth_ipaddr *addr;
83
84 if (query->is_multicast) {
85 hash_for_each_possible(card->ip_mc_htable, addr, hnode, key)
86 if (qeth_l3_addr_match_ip(addr, query))
87 return addr;
88 } else {
89 hash_for_each_possible(card->ip_htable, addr, hnode, key)
90 if (qeth_l3_addr_match_ip(addr, query))
91 return addr;
92 }
93 return NULL;
94}
95
Frank Blaschka4a71df52008-02-15 09:19:42 +010096static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
97{
98 int i, j;
99 u8 octet;
100
101 for (i = 0; i < len; ++i) {
102 octet = addr[i];
103 for (j = 7; j >= 0; --j) {
104 bits[i*8 + j] = octet & 1;
105 octet >>= 1;
106 }
107 }
108}
109
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100110static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
111 struct qeth_ipaddr *addr)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100112{
113 struct qeth_ipato_entry *ipatoe;
114 u8 addr_bits[128] = {0, };
115 u8 ipatoe_bits[128] = {0, };
116 int rc = 0;
117
118 if (!card->ipato.enabled)
Gustavo A. R. Silva1a363b02018-08-09 14:48:04 +0200119 return false;
Julian Wiedmannb22d73d62017-12-13 18:56:30 +0100120 if (addr->type != QETH_IP_TYPE_NORMAL)
Gustavo A. R. Silva1a363b02018-08-09 14:48:04 +0200121 return false;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100122
123 qeth_l3_convert_addr_to_bits((u8 *) &addr->u, addr_bits,
124 (addr->proto == QETH_PROT_IPV4)? 4:16);
125 list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
126 if (addr->proto != ipatoe->proto)
127 continue;
128 qeth_l3_convert_addr_to_bits(ipatoe->addr, ipatoe_bits,
129 (ipatoe->proto == QETH_PROT_IPV4) ?
130 4 : 16);
131 if (addr->proto == QETH_PROT_IPV4)
132 rc = !memcmp(addr_bits, ipatoe_bits,
133 min(32, ipatoe->mask_bits));
134 else
135 rc = !memcmp(addr_bits, ipatoe_bits,
136 min(128, ipatoe->mask_bits));
137 if (rc)
138 break;
139 }
140 /* invert? */
141 if ((addr->proto == QETH_PROT_IPV4) && card->ipato.invert4)
142 rc = !rc;
143 else if ((addr->proto == QETH_PROT_IPV6) && card->ipato.invert6)
144 rc = !rc;
145
146 return rc;
147}
148
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100149static int qeth_l3_delete_ip(struct qeth_card *card,
150 struct qeth_ipaddr *tmp_addr)
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200151{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100152 int rc = 0;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200153 struct qeth_ipaddr *addr;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100154
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100155 if (tmp_addr->type == QETH_IP_TYPE_RXIP)
156 QETH_CARD_TEXT(card, 2, "delrxip");
157 else if (tmp_addr->type == QETH_IP_TYPE_VIPA)
158 QETH_CARD_TEXT(card, 2, "delvipa");
159 else
160 QETH_CARD_TEXT(card, 2, "delip");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100161
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200162 if (tmp_addr->proto == QETH_PROT_IPV4)
163 QETH_CARD_HEX(card, 4, &tmp_addr->u.a4.addr, 4);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100164 else {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200165 QETH_CARD_HEX(card, 4, &tmp_addr->u.a6.addr, 8);
166 QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100167 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200168
Julian Wiedmannc5c48c52018-02-27 18:58:16 +0100169 addr = qeth_l3_find_addr_by_ip(card, tmp_addr);
170 if (!addr || !qeth_l3_addr_match_all(addr, tmp_addr))
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200171 return -ENOENT;
172
173 addr->ref_counter--;
Julian Wiedmann4964c662018-02-27 18:58:15 +0100174 if (addr->type == QETH_IP_TYPE_NORMAL && addr->ref_counter > 0)
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200175 return rc;
176 if (addr->in_progress)
177 return -EINPROGRESS;
178
Julian Wiedmann98d823a2018-02-27 18:58:13 +0100179 if (qeth_card_hw_is_reachable(card))
180 rc = qeth_l3_deregister_addr_entry(card, addr);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200181
182 hash_del(&addr->hnode);
183 kfree(addr);
184
Frank Blaschka4a71df52008-02-15 09:19:42 +0100185 return rc;
186}
187
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100188static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100189{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100190 int rc = 0;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200191 struct qeth_ipaddr *addr;
Julian Wiedmannc5c48c52018-02-27 18:58:16 +0100192 char buf[40];
Frank Blaschka4a71df52008-02-15 09:19:42 +0100193
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100194 if (tmp_addr->type == QETH_IP_TYPE_RXIP)
195 QETH_CARD_TEXT(card, 2, "addrxip");
196 else if (tmp_addr->type == QETH_IP_TYPE_VIPA)
197 QETH_CARD_TEXT(card, 2, "addvipa");
198 else
199 QETH_CARD_TEXT(card, 2, "addip");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200200
201 if (tmp_addr->proto == QETH_PROT_IPV4)
202 QETH_CARD_HEX(card, 4, &tmp_addr->u.a4.addr, 4);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100203 else {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200204 QETH_CARD_HEX(card, 4, &tmp_addr->u.a6.addr, 8);
205 QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100206 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200207
Julian Wiedmannc5c48c52018-02-27 18:58:16 +0100208 addr = qeth_l3_find_addr_by_ip(card, tmp_addr);
209 if (addr) {
210 if (tmp_addr->type != QETH_IP_TYPE_NORMAL)
211 return -EADDRINUSE;
212 if (qeth_l3_addr_match_all(addr, tmp_addr)) {
213 addr->ref_counter++;
214 return 0;
215 }
216 qeth_l3_ipaddr_to_string(tmp_addr->proto, (u8 *)&tmp_addr->u,
217 buf);
218 dev_warn(&card->gdev->dev,
219 "Registering IP address %s failed\n", buf);
220 return -EADDRINUSE;
221 } else {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200222 addr = qeth_l3_get_addr_buffer(tmp_addr->proto);
223 if (!addr)
224 return -ENOMEM;
225
226 memcpy(addr, tmp_addr, sizeof(struct qeth_ipaddr));
227 addr->ref_counter = 1;
228
Julian Wiedmannb22d73d62017-12-13 18:56:30 +0100229 if (qeth_l3_is_addr_covered_by_ipato(card, addr)) {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200230 QETH_CARD_TEXT(card, 2, "tkovaddr");
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100231 addr->ipato = 1;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200232 }
233 hash_add(card->ip_htable, &addr->hnode,
234 qeth_l3_ipaddr_hash(addr));
235
Ursula Brauna7531c12016-09-15 14:39:23 +0200236 if (!qeth_card_hw_is_reachable(card)) {
237 addr->disp_flag = QETH_DISP_ADDR_ADD;
238 return 0;
239 }
240
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200241 /* qeth_l3_register_addr_entry can go to sleep
242 * if we add a IPV4 addr. It is caused by the reason
243 * that SETIP ipa cmd starts ARP staff for IPV4 addr.
244 * Thus we should unlock spinlock, and make a protection
245 * using in_progress variable to indicate that there is
246 * an hardware operation with this IPV4 address
247 */
248 if (addr->proto == QETH_PROT_IPV4) {
249 addr->in_progress = 1;
250 spin_unlock_bh(&card->ip_lock);
251 rc = qeth_l3_register_addr_entry(card, addr);
252 spin_lock_bh(&card->ip_lock);
253 addr->in_progress = 0;
254 } else
255 rc = qeth_l3_register_addr_entry(card, addr);
256
257 if (!rc || (rc == IPA_RC_DUPLICATE_IP_ADDRESS) ||
258 (rc == IPA_RC_LAN_OFFLINE)) {
259 addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
260 if (addr->ref_counter < 1) {
Julian Wiedmann14d066c2018-02-27 18:58:14 +0100261 qeth_l3_deregister_addr_entry(card, addr);
262 hash_del(&addr->hnode);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200263 kfree(addr);
264 }
265 } else {
266 hash_del(&addr->hnode);
267 kfree(addr);
268 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200269 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100270 return rc;
271}
272
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200273static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100274{
275 struct qeth_ipaddr *addr;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200276 struct hlist_node *tmp;
277 int i;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100278
Carsten Otte847a50f2010-06-21 22:57:05 +0000279 QETH_CARD_TEXT(card, 4, "clearip");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200280
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200281 spin_lock_bh(&card->ip_lock);
282
283 hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) {
284 if (!recover) {
285 hash_del(&addr->hnode);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100286 kfree(addr);
287 continue;
288 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200289 addr->disp_flag = QETH_DISP_ADDR_ADD;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100290 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200291
292 spin_unlock_bh(&card->ip_lock);
293
294 spin_lock_bh(&card->mclock);
295
296 hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
297 hash_del(&addr->hnode);
298 kfree(addr);
299 }
300
301 spin_unlock_bh(&card->mclock);
302
303
Frank Blaschka4a71df52008-02-15 09:19:42 +0100304}
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200305static void qeth_l3_recover_ip(struct qeth_card *card)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100306{
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200307 struct qeth_ipaddr *addr;
308 struct hlist_node *tmp;
309 int i;
310 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100311
Ursula Brauna7531c12016-09-15 14:39:23 +0200312 QETH_CARD_TEXT(card, 4, "recovrip");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100313
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200314 spin_lock_bh(&card->ip_lock);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100315
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200316 hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) {
Julian Wiedmann98d823a2018-02-27 18:58:13 +0100317 if (addr->disp_flag == QETH_DISP_ADDR_ADD) {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200318 if (addr->proto == QETH_PROT_IPV4) {
319 addr->in_progress = 1;
320 spin_unlock_bh(&card->ip_lock);
321 rc = qeth_l3_register_addr_entry(card, addr);
322 spin_lock_bh(&card->ip_lock);
323 addr->in_progress = 0;
324 } else
325 rc = qeth_l3_register_addr_entry(card, addr);
326
327 if (!rc) {
328 addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
Ursula Brauna7531c12016-09-15 14:39:23 +0200329 if (addr->ref_counter < 1)
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200330 qeth_l3_delete_ip(card, addr);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200331 } else {
332 hash_del(&addr->hnode);
333 kfree(addr);
334 }
335 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100336 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200337
338 spin_unlock_bh(&card->ip_lock);
339
Frank Blaschka4a71df52008-02-15 09:19:42 +0100340}
341
342static int qeth_l3_send_setdelmc(struct qeth_card *card,
343 struct qeth_ipaddr *addr, int ipacmd)
344{
345 int rc;
346 struct qeth_cmd_buffer *iob;
347 struct qeth_ipa_cmd *cmd;
348
Carsten Otte847a50f2010-06-21 22:57:05 +0000349 QETH_CARD_TEXT(card, 4, "setdelmc");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100350
351 iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
Thomas Richter1aec42b2015-01-21 13:39:10 +0100352 if (!iob)
353 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +0100354 cmd = __ipa_cmd(iob);
Julian Wiedmann99f0b852017-12-20 20:11:01 +0100355 ether_addr_copy(cmd->data.setdelipm.mac, addr->mac);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100356 if (addr->proto == QETH_PROT_IPV6)
357 memcpy(cmd->data.setdelipm.ip6, &addr->u.a6.addr,
358 sizeof(struct in6_addr));
359 else
360 memcpy(&cmd->data.setdelipm.ip4, &addr->u.a4.addr, 4);
361
362 rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
363
364 return rc;
365}
366
367static void qeth_l3_fill_netmask(u8 *netmask, unsigned int len)
368{
369 int i, j;
370 for (i = 0; i < 16; i++) {
371 j = (len) - (i * 8);
372 if (j >= 8)
373 netmask[i] = 0xff;
374 else if (j > 0)
375 netmask[i] = (u8)(0xFF00 >> j);
376 else
377 netmask[i] = 0;
378 }
379}
380
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100381static u32 qeth_l3_get_setdelip_flags(struct qeth_ipaddr *addr, bool set)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100382{
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100383 switch (addr->type) {
384 case QETH_IP_TYPE_RXIP:
385 return (set) ? QETH_IPA_SETIP_TAKEOVER_FLAG : 0;
386 case QETH_IP_TYPE_VIPA:
387 return (set) ? QETH_IPA_SETIP_VIPA_FLAG :
388 QETH_IPA_DELIP_VIPA_FLAG;
389 default:
390 return (set && addr->ipato) ? QETH_IPA_SETIP_TAKEOVER_FLAG : 0;
391 }
392}
393
394static int qeth_l3_send_setdelip(struct qeth_card *card,
395 struct qeth_ipaddr *addr,
396 enum qeth_ipa_cmds ipacmd)
397{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100398 struct qeth_cmd_buffer *iob;
399 struct qeth_ipa_cmd *cmd;
400 __u8 netmask[16];
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100401 u32 flags;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100402
Carsten Otte847a50f2010-06-21 22:57:05 +0000403 QETH_CARD_TEXT(card, 4, "setdelip");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100404
405 iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
Thomas Richter1aec42b2015-01-21 13:39:10 +0100406 if (!iob)
407 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +0100408 cmd = __ipa_cmd(iob);
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100409
410 flags = qeth_l3_get_setdelip_flags(addr, ipacmd == IPA_CMD_SETIP);
411 QETH_CARD_TEXT_(card, 4, "flags%02X", flags);
412
Frank Blaschka4a71df52008-02-15 09:19:42 +0100413 if (addr->proto == QETH_PROT_IPV6) {
414 memcpy(cmd->data.setdelip6.ip_addr, &addr->u.a6.addr,
415 sizeof(struct in6_addr));
416 qeth_l3_fill_netmask(netmask, addr->u.a6.pfxlen);
417 memcpy(cmd->data.setdelip6.mask, netmask,
418 sizeof(struct in6_addr));
419 cmd->data.setdelip6.flags = flags;
420 } else {
421 memcpy(cmd->data.setdelip4.ip_addr, &addr->u.a4.addr, 4);
422 memcpy(cmd->data.setdelip4.mask, &addr->u.a4.mask, 4);
423 cmd->data.setdelip4.flags = flags;
424 }
425
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100426 return qeth_send_ipa_cmd(card, iob, NULL, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100427}
428
429static int qeth_l3_send_setrouting(struct qeth_card *card,
430 enum qeth_routing_types type, enum qeth_prot_versions prot)
431{
432 int rc;
433 struct qeth_ipa_cmd *cmd;
434 struct qeth_cmd_buffer *iob;
435
Carsten Otte847a50f2010-06-21 22:57:05 +0000436 QETH_CARD_TEXT(card, 4, "setroutg");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100437 iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot);
Thomas Richter1aec42b2015-01-21 13:39:10 +0100438 if (!iob)
439 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +0100440 cmd = __ipa_cmd(iob);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100441 cmd->data.setrtg.type = (type);
442 rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
443
444 return rc;
445}
446
Stefan Raspl82e2e782013-03-18 20:04:43 +0000447static int qeth_l3_correct_routing_type(struct qeth_card *card,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100448 enum qeth_routing_types *type, enum qeth_prot_versions prot)
449{
450 if (card->info.type == QETH_CARD_TYPE_IQD) {
451 switch (*type) {
452 case NO_ROUTER:
453 case PRIMARY_CONNECTOR:
454 case SECONDARY_CONNECTOR:
455 case MULTICAST_ROUTER:
Stefan Raspl82e2e782013-03-18 20:04:43 +0000456 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100457 default:
458 goto out_inval;
459 }
460 } else {
461 switch (*type) {
462 case NO_ROUTER:
463 case PRIMARY_ROUTER:
464 case SECONDARY_ROUTER:
Stefan Raspl82e2e782013-03-18 20:04:43 +0000465 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100466 case MULTICAST_ROUTER:
467 if (qeth_is_ipafunc_supported(card, prot,
468 IPA_OSA_MC_ROUTER))
Stefan Raspl82e2e782013-03-18 20:04:43 +0000469 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100470 default:
471 goto out_inval;
472 }
473 }
474out_inval:
Frank Blaschka4a71df52008-02-15 09:19:42 +0100475 *type = NO_ROUTER;
Stefan Raspl82e2e782013-03-18 20:04:43 +0000476 return -EINVAL;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100477}
478
479int qeth_l3_setrouting_v4(struct qeth_card *card)
480{
481 int rc;
482
Carsten Otte847a50f2010-06-21 22:57:05 +0000483 QETH_CARD_TEXT(card, 3, "setrtg4");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100484
Stefan Raspl82e2e782013-03-18 20:04:43 +0000485 rc = qeth_l3_correct_routing_type(card, &card->options.route4.type,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100486 QETH_PROT_IPV4);
Stefan Raspl82e2e782013-03-18 20:04:43 +0000487 if (rc)
488 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100489
490 rc = qeth_l3_send_setrouting(card, card->options.route4.type,
491 QETH_PROT_IPV4);
492 if (rc) {
493 card->options.route4.type = NO_ROUTER;
Julian Wiedmanne19e5be2018-11-02 19:04:08 +0100494 QETH_DBF_MESSAGE(2, "Error (%#06x) while setting routing type on device %x. Type set to 'no router'.\n",
495 rc, CARD_DEVID(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100496 }
497 return rc;
498}
499
500int qeth_l3_setrouting_v6(struct qeth_card *card)
501{
502 int rc = 0;
503
Carsten Otte847a50f2010-06-21 22:57:05 +0000504 QETH_CARD_TEXT(card, 3, "setrtg6");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100505
506 if (!qeth_is_supported(card, IPA_IPV6))
507 return 0;
Stefan Raspl82e2e782013-03-18 20:04:43 +0000508 rc = qeth_l3_correct_routing_type(card, &card->options.route6.type,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100509 QETH_PROT_IPV6);
Stefan Raspl82e2e782013-03-18 20:04:43 +0000510 if (rc)
511 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100512
513 rc = qeth_l3_send_setrouting(card, card->options.route6.type,
514 QETH_PROT_IPV6);
515 if (rc) {
516 card->options.route6.type = NO_ROUTER;
Julian Wiedmanne19e5be2018-11-02 19:04:08 +0100517 QETH_DBF_MESSAGE(2, "Error (%#06x) while setting routing type on device %x. Type set to 'no router'.\n",
518 rc, CARD_DEVID(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100519 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100520 return rc;
521}
522
523/*
524 * IP address takeover related functions
525 */
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100526
527/**
528 * qeth_l3_update_ipato() - Update 'takeover' property, for all NORMAL IPs.
529 *
530 * Caller must hold ip_lock.
531 */
532void qeth_l3_update_ipato(struct qeth_card *card)
533{
534 struct qeth_ipaddr *addr;
535 unsigned int i;
536
537 hash_for_each(card->ip_htable, i, addr, hnode) {
538 if (addr->type != QETH_IP_TYPE_NORMAL)
539 continue;
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100540 addr->ipato = qeth_l3_is_addr_covered_by_ipato(card, addr);
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100541 }
542}
543
Frank Blaschka4a71df52008-02-15 09:19:42 +0100544static void qeth_l3_clear_ipato_list(struct qeth_card *card)
545{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100546 struct qeth_ipato_entry *ipatoe, *tmp;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100547
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200548 spin_lock_bh(&card->ip_lock);
549
Frank Blaschka4a71df52008-02-15 09:19:42 +0100550 list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
551 list_del(&ipatoe->entry);
552 kfree(ipatoe);
553 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200554
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100555 qeth_l3_update_ipato(card);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200556 spin_unlock_bh(&card->ip_lock);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100557}
558
559int qeth_l3_add_ipato_entry(struct qeth_card *card,
560 struct qeth_ipato_entry *new)
561{
562 struct qeth_ipato_entry *ipatoe;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100563 int rc = 0;
564
Carsten Otte847a50f2010-06-21 22:57:05 +0000565 QETH_CARD_TEXT(card, 2, "addipato");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200566
567 spin_lock_bh(&card->ip_lock);
568
Frank Blaschka4a71df52008-02-15 09:19:42 +0100569 list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
570 if (ipatoe->proto != new->proto)
571 continue;
572 if (!memcmp(ipatoe->addr, new->addr,
573 (ipatoe->proto == QETH_PROT_IPV4)? 4:16) &&
574 (ipatoe->mask_bits == new->mask_bits)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100575 rc = -EEXIST;
576 break;
577 }
578 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200579
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100580 if (!rc) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100581 list_add_tail(&new->entry, &card->ipato.entries);
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100582 qeth_l3_update_ipato(card);
583 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100584
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200585 spin_unlock_bh(&card->ip_lock);
586
Frank Blaschka4a71df52008-02-15 09:19:42 +0100587 return rc;
588}
589
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100590int qeth_l3_del_ipato_entry(struct qeth_card *card,
591 enum qeth_prot_versions proto, u8 *addr,
592 int mask_bits)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100593{
594 struct qeth_ipato_entry *ipatoe, *tmp;
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100595 int rc = -ENOENT;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100596
Carsten Otte847a50f2010-06-21 22:57:05 +0000597 QETH_CARD_TEXT(card, 2, "delipato");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200598
599 spin_lock_bh(&card->ip_lock);
600
Frank Blaschka4a71df52008-02-15 09:19:42 +0100601 list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
602 if (ipatoe->proto != proto)
603 continue;
604 if (!memcmp(ipatoe->addr, addr,
605 (proto == QETH_PROT_IPV4)? 4:16) &&
606 (ipatoe->mask_bits == mask_bits)) {
607 list_del(&ipatoe->entry);
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100608 qeth_l3_update_ipato(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100609 kfree(ipatoe);
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100610 rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100611 }
612 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200613
614 spin_unlock_bh(&card->ip_lock);
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100615 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100616}
617
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100618int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip,
619 enum qeth_ip_types type,
620 enum qeth_prot_versions proto)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100621{
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100622 struct qeth_ipaddr addr;
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100623 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100624
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100625 qeth_l3_init_ipaddr(&addr, type, proto);
626 if (proto == QETH_PROT_IPV4)
627 memcpy(&addr.u.a4.addr, ip, 4);
628 else
629 memcpy(&addr.u.a6.addr, ip, 16);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200630
631 spin_lock_bh(&card->ip_lock);
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100632 rc = add ? qeth_l3_add_ip(card, &addr) : qeth_l3_delete_ip(card, &addr);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200633 spin_unlock_bh(&card->ip_lock);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100634 return rc;
635}
636
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100637int qeth_l3_modify_hsuid(struct qeth_card *card, bool add)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100638{
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100639 struct qeth_ipaddr addr;
640 int rc, i;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100641
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100642 qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6);
643 addr.u.a6.addr.s6_addr[0] = 0xfe;
644 addr.u.a6.addr.s6_addr[1] = 0x80;
645 for (i = 0; i < 8; i++)
646 addr.u.a6.addr.s6_addr[8+i] = card->options.hsuid[i];
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200647
648 spin_lock_bh(&card->ip_lock);
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100649 rc = add ? qeth_l3_add_ip(card, &addr) : qeth_l3_delete_ip(card, &addr);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200650 spin_unlock_bh(&card->ip_lock);
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100651 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100652}
653
654static int qeth_l3_register_addr_entry(struct qeth_card *card,
655 struct qeth_ipaddr *addr)
656{
657 char buf[50];
658 int rc = 0;
659 int cnt = 3;
660
Julian Wiedmannbd74a7f2018-11-02 19:04:09 +0100661 if (card->options.sniffer)
662 return 0;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200663
Frank Blaschka4a71df52008-02-15 09:19:42 +0100664 if (addr->proto == QETH_PROT_IPV4) {
Carsten Otte847a50f2010-06-21 22:57:05 +0000665 QETH_CARD_TEXT(card, 2, "setaddr4");
666 QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100667 } else if (addr->proto == QETH_PROT_IPV6) {
Carsten Otte847a50f2010-06-21 22:57:05 +0000668 QETH_CARD_TEXT(card, 2, "setaddr6");
669 QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
670 QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100671 } else {
Carsten Otte847a50f2010-06-21 22:57:05 +0000672 QETH_CARD_TEXT(card, 2, "setaddr?");
673 QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100674 }
675 do {
676 if (addr->is_multicast)
677 rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_SETIPM);
678 else
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100679 rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_SETIP);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100680 if (rc)
Carsten Otte847a50f2010-06-21 22:57:05 +0000681 QETH_CARD_TEXT(card, 2, "failed");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100682 } while ((--cnt > 0) && rc);
683 if (rc) {
Carsten Otte847a50f2010-06-21 22:57:05 +0000684 QETH_CARD_TEXT(card, 2, "FAILED");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100685 qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100686 dev_warn(&card->gdev->dev,
687 "Registering IP address %s failed\n", buf);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100688 }
689 return rc;
690}
691
692static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
693 struct qeth_ipaddr *addr)
694{
695 int rc = 0;
696
Julian Wiedmannbd74a7f2018-11-02 19:04:09 +0100697 if (card->options.sniffer)
698 return 0;
699
Frank Blaschka4a71df52008-02-15 09:19:42 +0100700 if (addr->proto == QETH_PROT_IPV4) {
Carsten Otte847a50f2010-06-21 22:57:05 +0000701 QETH_CARD_TEXT(card, 2, "deladdr4");
702 QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100703 } else if (addr->proto == QETH_PROT_IPV6) {
Carsten Otte847a50f2010-06-21 22:57:05 +0000704 QETH_CARD_TEXT(card, 2, "deladdr6");
705 QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
706 QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100707 } else {
Carsten Otte847a50f2010-06-21 22:57:05 +0000708 QETH_CARD_TEXT(card, 2, "deladdr?");
709 QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100710 }
711 if (addr->is_multicast)
712 rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_DELIPM);
713 else
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100714 rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP);
Frank Blaschkac4cef072008-07-14 09:59:31 +0200715 if (rc)
Carsten Otte847a50f2010-06-21 22:57:05 +0000716 QETH_CARD_TEXT(card, 2, "failed");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100717
718 return rc;
719}
720
Frank Blaschka4a71df52008-02-15 09:19:42 +0100721static int qeth_l3_setadapter_parms(struct qeth_card *card)
722{
Julian Wiedmann699d3fe2017-08-15 17:02:41 +0200723 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100724
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +0200725 QETH_DBF_TEXT(SETUP, 2, "setadprm");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100726
Frank Blaschka4a71df52008-02-15 09:19:42 +0100727 if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) {
728 rc = qeth_setadpparms_change_macaddr(card);
729 if (rc)
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100730 dev_warn(&card->gdev->dev, "Reading the adapter MAC"
Heiko Carstens6ea2fde2009-01-04 17:36:32 -0800731 " address failed\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100732 }
733
Frank Blaschka4a71df52008-02-15 09:19:42 +0100734 return rc;
735}
736
Frank Blaschka4a71df52008-02-15 09:19:42 +0100737static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card)
738{
739 int rc;
740
Carsten Otte847a50f2010-06-21 22:57:05 +0000741 QETH_CARD_TEXT(card, 3, "ipaarp");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100742
743 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100744 dev_info(&card->gdev->dev,
745 "ARP processing not supported on %s!\n",
746 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100747 return 0;
748 }
Thomas Richter4d7def22015-09-18 16:06:51 +0200749 rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
750 IPA_CMD_ASS_START, 0);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100751 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100752 dev_warn(&card->gdev->dev,
753 "Starting ARP processing support for %s failed\n",
754 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100755 }
756 return rc;
757}
758
Frank Blaschka4a71df52008-02-15 09:19:42 +0100759static int qeth_l3_start_ipa_source_mac(struct qeth_card *card)
760{
761 int rc;
762
Carsten Otte847a50f2010-06-21 22:57:05 +0000763 QETH_CARD_TEXT(card, 3, "stsrcmac");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100764
Frank Blaschka4a71df52008-02-15 09:19:42 +0100765 if (!qeth_is_supported(card, IPA_SOURCE_MAC)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100766 dev_info(&card->gdev->dev,
Ursula Braunfe94e2e2009-01-04 17:34:52 -0800767 "Inbound source MAC-address not supported on %s\n",
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100768 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100769 return -EOPNOTSUPP;
770 }
771
Thomas Richter4d7def22015-09-18 16:06:51 +0200772 rc = qeth_send_simple_setassparms(card, IPA_SOURCE_MAC,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100773 IPA_CMD_ASS_START, 0);
774 if (rc)
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100775 dev_warn(&card->gdev->dev,
Ursula Braunfe94e2e2009-01-04 17:34:52 -0800776 "Starting source MAC-address support for %s failed\n",
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100777 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100778 return rc;
779}
780
781static int qeth_l3_start_ipa_vlan(struct qeth_card *card)
782{
783 int rc = 0;
784
Carsten Otte847a50f2010-06-21 22:57:05 +0000785 QETH_CARD_TEXT(card, 3, "strtvlan");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100786
787 if (!qeth_is_supported(card, IPA_FULL_VLAN)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100788 dev_info(&card->gdev->dev,
789 "VLAN not supported on %s\n", QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100790 return -EOPNOTSUPP;
791 }
792
Thomas Richter4d7def22015-09-18 16:06:51 +0200793 rc = qeth_send_simple_setassparms(card, IPA_VLAN_PRIO,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100794 IPA_CMD_ASS_START, 0);
795 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100796 dev_warn(&card->gdev->dev,
797 "Starting VLAN support for %s failed\n",
798 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100799 } else {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100800 dev_info(&card->gdev->dev, "VLAN enabled\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100801 }
802 return rc;
803}
804
805static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
806{
807 int rc;
808
Carsten Otte847a50f2010-06-21 22:57:05 +0000809 QETH_CARD_TEXT(card, 3, "stmcast");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100810
811 if (!qeth_is_supported(card, IPA_MULTICASTING)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100812 dev_info(&card->gdev->dev,
813 "Multicast not supported on %s\n",
814 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100815 return -EOPNOTSUPP;
816 }
817
Thomas Richter4d7def22015-09-18 16:06:51 +0200818 rc = qeth_send_simple_setassparms(card, IPA_MULTICASTING,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100819 IPA_CMD_ASS_START, 0);
820 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100821 dev_warn(&card->gdev->dev,
822 "Starting multicast support for %s failed\n",
823 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100824 } else {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100825 dev_info(&card->gdev->dev, "Multicast enabled\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100826 card->dev->flags |= IFF_MULTICAST;
827 }
828 return rc;
829}
830
Frank Blaschka4a71df52008-02-15 09:19:42 +0100831static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
832{
833 int rc;
834
Carsten Otte847a50f2010-06-21 22:57:05 +0000835 QETH_CARD_TEXT(card, 3, "softipv6");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100836
Julian Wiedmann23274592017-06-06 14:33:44 +0200837 if (card->info.type == QETH_CARD_TYPE_IQD)
838 goto out;
839
Thomas Richter4d7def22015-09-18 16:06:51 +0200840 rc = qeth_send_simple_setassparms(card, IPA_IPV6,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100841 IPA_CMD_ASS_START, 3);
842 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100843 dev_err(&card->gdev->dev,
844 "Activating IPv6 support for %s failed\n",
845 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100846 return rc;
847 }
Kittipon Meesompopa8155b02018-04-26 09:42:21 +0200848 rc = qeth_send_simple_setassparms_v6(card, IPA_IPV6,
849 IPA_CMD_ASS_START, 0);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100850 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100851 dev_err(&card->gdev->dev,
852 "Activating IPv6 support for %s failed\n",
853 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100854 return rc;
855 }
Kittipon Meesompopa8155b02018-04-26 09:42:21 +0200856 rc = qeth_send_simple_setassparms_v6(card, IPA_PASSTHRU,
857 IPA_CMD_ASS_START, 0);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100858 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100859 dev_warn(&card->gdev->dev,
860 "Enabling the passthrough mode for %s failed\n",
861 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100862 return rc;
863 }
864out:
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100865 dev_info(&card->gdev->dev, "IPV6 enabled\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100866 return 0;
867}
Frank Blaschka4a71df52008-02-15 09:19:42 +0100868
869static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
870{
Carsten Otte847a50f2010-06-21 22:57:05 +0000871 QETH_CARD_TEXT(card, 3, "strtipv6");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100872
873 if (!qeth_is_supported(card, IPA_IPV6)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100874 dev_info(&card->gdev->dev,
875 "IPv6 not supported on %s\n", QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100876 return 0;
877 }
Julian Wiedmannc0622042017-12-20 20:10:58 +0100878 return qeth_l3_softsetup_ipv6(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100879}
880
881static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
882{
883 int rc;
884
Carsten Otte847a50f2010-06-21 22:57:05 +0000885 QETH_CARD_TEXT(card, 3, "stbrdcst");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100886 card->info.broadcast_capable = 0;
887 if (!qeth_is_supported(card, IPA_FILTERING)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100888 dev_info(&card->gdev->dev,
889 "Broadcast not supported on %s\n",
890 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100891 rc = -EOPNOTSUPP;
892 goto out;
893 }
Thomas Richter4d7def22015-09-18 16:06:51 +0200894 rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100895 IPA_CMD_ASS_START, 0);
896 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100897 dev_warn(&card->gdev->dev, "Enabling broadcast filtering for "
898 "%s failed\n", QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100899 goto out;
900 }
901
Thomas Richter4d7def22015-09-18 16:06:51 +0200902 rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100903 IPA_CMD_ASS_CONFIGURE, 1);
904 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100905 dev_warn(&card->gdev->dev,
906 "Setting up broadcast filtering for %s failed\n",
907 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100908 goto out;
909 }
910 card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO;
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100911 dev_info(&card->gdev->dev, "Broadcast enabled\n");
Thomas Richter4d7def22015-09-18 16:06:51 +0200912 rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100913 IPA_CMD_ASS_ENABLE, 1);
914 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100915 dev_warn(&card->gdev->dev, "Setting up broadcast echo "
916 "filtering for %s failed\n", QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100917 goto out;
918 }
919 card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO;
920out:
921 if (card->info.broadcast_capable)
922 card->dev->flags |= IFF_BROADCAST;
923 else
924 card->dev->flags &= ~IFF_BROADCAST;
925 return rc;
926}
927
Frank Blaschka4a71df52008-02-15 09:19:42 +0100928static int qeth_l3_start_ipassists(struct qeth_card *card)
929{
Carsten Otte847a50f2010-06-21 22:57:05 +0000930 QETH_CARD_TEXT(card, 3, "strtipas");
Einar Lueckd64ecc22009-11-12 00:11:41 +0000931
Stefan Raspl0f547612013-01-21 02:30:20 +0000932 if (qeth_set_access_ctrl_online(card, 0))
933 return -EIO;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100934 qeth_l3_start_ipa_arp_processing(card); /* go on*/
Frank Blaschka4a71df52008-02-15 09:19:42 +0100935 qeth_l3_start_ipa_source_mac(card); /* go on*/
936 qeth_l3_start_ipa_vlan(card); /* go on*/
937 qeth_l3_start_ipa_multicast(card); /* go on*/
938 qeth_l3_start_ipa_ipv6(card); /* go on*/
939 qeth_l3_start_ipa_broadcast(card); /* go on*/
Frank Blaschka4a71df52008-02-15 09:19:42 +0100940 return 0;
941}
942
Frank Blaschka4a71df52008-02-15 09:19:42 +0100943static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card,
944 struct qeth_reply *reply, unsigned long data)
945{
946 struct qeth_ipa_cmd *cmd;
947
948 cmd = (struct qeth_ipa_cmd *) data;
949 if (cmd->hdr.return_code == 0)
Julian Wiedmann99f0b852017-12-20 20:11:01 +0100950 ether_addr_copy(card->dev->dev_addr,
951 cmd->data.create_destroy_addr.unique_id);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100952 else
Joe Perches18336112012-07-12 22:33:10 -0700953 eth_random_addr(card->dev->dev_addr);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100954
955 return 0;
956}
957
958static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card)
959{
960 int rc = 0;
961 struct qeth_cmd_buffer *iob;
962 struct qeth_ipa_cmd *cmd;
963
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +0200964 QETH_DBF_TEXT(SETUP, 2, "hsrmac");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100965
966 iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
967 QETH_PROT_IPV6);
Thomas Richter1aec42b2015-01-21 13:39:10 +0100968 if (!iob)
969 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +0100970 cmd = __ipa_cmd(iob);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100971 *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) =
972 card->info.unique_id;
973
974 rc = qeth_send_ipa_cmd(card, iob, qeth_l3_iqd_read_initial_mac_cb,
975 NULL);
976 return rc;
977}
978
979static int qeth_l3_get_unique_id_cb(struct qeth_card *card,
980 struct qeth_reply *reply, unsigned long data)
981{
982 struct qeth_ipa_cmd *cmd;
983
984 cmd = (struct qeth_ipa_cmd *) data;
985 if (cmd->hdr.return_code == 0)
986 card->info.unique_id = *((__u16 *)
987 &cmd->data.create_destroy_addr.unique_id[6]);
988 else {
989 card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
990 UNIQUE_ID_NOT_BY_CARD;
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100991 dev_warn(&card->gdev->dev, "The network adapter failed to "
992 "generate a unique ID\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100993 }
994 return 0;
995}
996
997static int qeth_l3_get_unique_id(struct qeth_card *card)
998{
999 int rc = 0;
1000 struct qeth_cmd_buffer *iob;
1001 struct qeth_ipa_cmd *cmd;
1002
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02001003 QETH_DBF_TEXT(SETUP, 2, "guniqeid");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001004
1005 if (!qeth_is_supported(card, IPA_IPV6)) {
1006 card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
1007 UNIQUE_ID_NOT_BY_CARD;
1008 return 0;
1009 }
1010
1011 iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
1012 QETH_PROT_IPV6);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001013 if (!iob)
1014 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +01001015 cmd = __ipa_cmd(iob);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001016 *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) =
1017 card->info.unique_id;
1018
1019 rc = qeth_send_ipa_cmd(card, iob, qeth_l3_get_unique_id_cb, NULL);
1020 return rc;
1021}
1022
Ursula Braun76b11f82010-01-11 02:50:50 +00001023static int
1024qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
1025 unsigned long data)
1026{
1027 struct qeth_ipa_cmd *cmd;
1028 __u16 rc;
1029
1030 QETH_DBF_TEXT(SETUP, 2, "diastrcb");
1031
1032 cmd = (struct qeth_ipa_cmd *)data;
1033 rc = cmd->hdr.return_code;
Ursula Brauna9591892010-03-08 20:36:55 +00001034 if (rc)
Carsten Otte847a50f2010-06-21 22:57:05 +00001035 QETH_CARD_TEXT_(card, 2, "dxter%x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00001036 switch (cmd->data.diagass.action) {
1037 case QETH_DIAGS_CMD_TRACE_QUERY:
1038 break;
1039 case QETH_DIAGS_CMD_TRACE_DISABLE:
Ursula Brauna9591892010-03-08 20:36:55 +00001040 switch (rc) {
1041 case 0:
1042 case IPA_RC_INVALID_SUBCMD:
1043 card->info.promisc_mode = SET_PROMISC_MODE_OFF;
1044 dev_info(&card->gdev->dev, "The HiperSockets network "
1045 "traffic analyzer is deactivated\n");
1046 break;
1047 default:
1048 break;
1049 }
Ursula Braun76b11f82010-01-11 02:50:50 +00001050 break;
1051 case QETH_DIAGS_CMD_TRACE_ENABLE:
Ursula Brauna9591892010-03-08 20:36:55 +00001052 switch (rc) {
1053 case 0:
1054 card->info.promisc_mode = SET_PROMISC_MODE_ON;
1055 dev_info(&card->gdev->dev, "The HiperSockets network "
1056 "traffic analyzer is activated\n");
1057 break;
1058 case IPA_RC_HARDWARE_AUTH_ERROR:
1059 dev_warn(&card->gdev->dev, "The device is not "
1060 "authorized to run as a HiperSockets network "
1061 "traffic analyzer\n");
1062 break;
1063 case IPA_RC_TRACE_ALREADY_ACTIVE:
1064 dev_warn(&card->gdev->dev, "A HiperSockets "
1065 "network traffic analyzer is already "
1066 "active in the HiperSockets LAN\n");
1067 break;
1068 default:
1069 break;
1070 }
Ursula Braun76b11f82010-01-11 02:50:50 +00001071 break;
1072 default:
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001073 QETH_DBF_MESSAGE(2, "Unknown sniffer action (%#06x) on device %x\n",
1074 cmd->data.diagass.action, CARD_DEVID(card));
Ursula Braun76b11f82010-01-11 02:50:50 +00001075 }
1076
1077 return 0;
1078}
1079
1080static int
1081qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
1082{
1083 struct qeth_cmd_buffer *iob;
1084 struct qeth_ipa_cmd *cmd;
1085
1086 QETH_DBF_TEXT(SETUP, 2, "diagtrac");
1087
1088 iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001089 if (!iob)
1090 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +01001091 cmd = __ipa_cmd(iob);
Ursula Braun76b11f82010-01-11 02:50:50 +00001092 cmd->data.diagass.subcmd_len = 16;
1093 cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE;
1094 cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET;
1095 cmd->data.diagass.action = diags_cmd;
1096 return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
1097}
1098
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001099static void
1100qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
1101{
Frank Blaschka4a71df52008-02-15 09:19:42 +01001102 struct ip_mc_list *im4;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001103 struct qeth_ipaddr *tmp, *ipm;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001104
Carsten Otte847a50f2010-06-21 22:57:05 +00001105 QETH_CARD_TEXT(card, 4, "addmc");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001106
1107 tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
Julian Wiedmann8d9183d2017-12-20 20:10:57 +01001108 if (!tmp)
1109 return;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001110
Sachin Santf3aa3132010-11-26 02:41:17 +00001111 for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL;
1112 im4 = rcu_dereference(im4->next_rcu)) {
Julian Wiedmann8d9183d2017-12-20 20:10:57 +01001113 ip_eth_mc_map(im4->multiaddr, tmp->mac);
Hans Wippel6bee4e22017-04-07 09:15:36 +02001114 tmp->u.a4.addr = be32_to_cpu(im4->multiaddr);
Julian Wiedmannbc3ab7052017-12-01 10:14:49 +01001115 tmp->is_multicast = 1;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001116
Julian Wiedmannc5c48c52018-02-27 18:58:16 +01001117 ipm = qeth_l3_find_addr_by_ip(card, tmp);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001118 if (ipm) {
Julian Wiedmannc5c48c52018-02-27 18:58:16 +01001119 /* for mcast, by-IP match means full match */
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001120 ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
1121 } else {
1122 ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
1123 if (!ipm)
1124 continue;
Julian Wiedmann99f0b852017-12-20 20:11:01 +01001125 ether_addr_copy(ipm->mac, tmp->mac);
Hans Wippel6bee4e22017-04-07 09:15:36 +02001126 ipm->u.a4.addr = be32_to_cpu(im4->multiaddr);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001127 ipm->is_multicast = 1;
1128 ipm->disp_flag = QETH_DISP_ADDR_ADD;
1129 hash_add(card->ip_mc_htable,
1130 &ipm->hnode, qeth_l3_ipaddr_hash(ipm));
1131 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001132 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001133
1134 kfree(tmp);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001135}
1136
Jiri Pirko0347af52013-01-03 22:48:58 +00001137/* called with rcu_read_lock */
Frank Blaschka4a71df52008-02-15 09:19:42 +01001138static void qeth_l3_add_vlan_mc(struct qeth_card *card)
1139{
1140 struct in_device *in_dev;
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001141 u16 vid;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001142
Carsten Otte847a50f2010-06-21 22:57:05 +00001143 QETH_CARD_TEXT(card, 4, "addmcvl");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001144
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001145 if (!qeth_is_supported(card, IPA_FULL_VLAN))
Frank Blaschka4a71df52008-02-15 09:19:42 +01001146 return;
1147
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001148 for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
1149 struct net_device *netdev;
1150
dingtianhongf06c7f9f2014-05-09 14:58:05 +08001151 netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q),
Patrick McHardy91b1c1a2013-04-21 00:09:34 +00001152 vid);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001153 if (netdev == NULL ||
1154 !(netdev->flags & IFF_UP))
1155 continue;
Jiri Pirko0347af52013-01-03 22:48:58 +00001156 in_dev = __in_dev_get_rcu(netdev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001157 if (!in_dev)
1158 continue;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001159 qeth_l3_add_mc_to_hash(card, in_dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001160 }
1161}
1162
1163static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)
1164{
1165 struct in_device *in4_dev;
1166
Carsten Otte847a50f2010-06-21 22:57:05 +00001167 QETH_CARD_TEXT(card, 4, "chkmcv4");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001168
Sachin Santf3aa3132010-11-26 02:41:17 +00001169 rcu_read_lock();
Jiri Pirko0347af52013-01-03 22:48:58 +00001170 in4_dev = __in_dev_get_rcu(card->dev);
1171 if (in4_dev == NULL)
1172 goto unlock;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001173 qeth_l3_add_mc_to_hash(card, in4_dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001174 qeth_l3_add_vlan_mc(card);
Jiri Pirko0347af52013-01-03 22:48:58 +00001175unlock:
Sachin Santf3aa3132010-11-26 02:41:17 +00001176 rcu_read_unlock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01001177}
1178
Julian Wiedmannc0622042017-12-20 20:10:58 +01001179static void qeth_l3_add_mc6_to_hash(struct qeth_card *card,
1180 struct inet6_dev *in6_dev)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001181{
1182 struct qeth_ipaddr *ipm;
1183 struct ifmcaddr6 *im6;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001184 struct qeth_ipaddr *tmp;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001185
Carsten Otte847a50f2010-06-21 22:57:05 +00001186 QETH_CARD_TEXT(card, 4, "addmc6");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001187
1188 tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
Julian Wiedmann8d9183d2017-12-20 20:10:57 +01001189 if (!tmp)
1190 return;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001191
Frank Blaschka4a71df52008-02-15 09:19:42 +01001192 for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
Julian Wiedmann8d9183d2017-12-20 20:10:57 +01001193 ipv6_eth_mc_map(&im6->mca_addr, tmp->mac);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001194 memcpy(&tmp->u.a6.addr, &im6->mca_addr.s6_addr,
1195 sizeof(struct in6_addr));
1196 tmp->is_multicast = 1;
1197
Julian Wiedmannc5c48c52018-02-27 18:58:16 +01001198 ipm = qeth_l3_find_addr_by_ip(card, tmp);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001199 if (ipm) {
Julian Wiedmannc5c48c52018-02-27 18:58:16 +01001200 /* for mcast, by-IP match means full match */
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001201 ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
1202 continue;
1203 }
1204
Frank Blaschka4a71df52008-02-15 09:19:42 +01001205 ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
1206 if (!ipm)
1207 continue;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001208
Julian Wiedmann99f0b852017-12-20 20:11:01 +01001209 ether_addr_copy(ipm->mac, tmp->mac);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001210 memcpy(&ipm->u.a6.addr, &im6->mca_addr.s6_addr,
1211 sizeof(struct in6_addr));
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001212 ipm->is_multicast = 1;
1213 ipm->disp_flag = QETH_DISP_ADDR_ADD;
1214 hash_add(card->ip_mc_htable,
1215 &ipm->hnode, qeth_l3_ipaddr_hash(ipm));
1216
Frank Blaschka4a71df52008-02-15 09:19:42 +01001217 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001218 kfree(tmp);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001219}
1220
Jiri Pirko0347af52013-01-03 22:48:58 +00001221/* called with rcu_read_lock */
Frank Blaschka4a71df52008-02-15 09:19:42 +01001222static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
1223{
1224 struct inet6_dev *in_dev;
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001225 u16 vid;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001226
Carsten Otte847a50f2010-06-21 22:57:05 +00001227 QETH_CARD_TEXT(card, 4, "admc6vl");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001228
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001229 if (!qeth_is_supported(card, IPA_FULL_VLAN))
Frank Blaschka4a71df52008-02-15 09:19:42 +01001230 return;
1231
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001232 for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
1233 struct net_device *netdev;
1234
dingtianhongf06c7f9f2014-05-09 14:58:05 +08001235 netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q),
Patrick McHardy91b1c1a2013-04-21 00:09:34 +00001236 vid);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001237 if (netdev == NULL ||
1238 !(netdev->flags & IFF_UP))
1239 continue;
1240 in_dev = in6_dev_get(netdev);
1241 if (!in_dev)
1242 continue;
1243 read_lock_bh(&in_dev->lock);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001244 qeth_l3_add_mc6_to_hash(card, in_dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001245 read_unlock_bh(&in_dev->lock);
1246 in6_dev_put(in_dev);
1247 }
1248}
1249
1250static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)
1251{
1252 struct inet6_dev *in6_dev;
1253
Carsten Otte847a50f2010-06-21 22:57:05 +00001254 QETH_CARD_TEXT(card, 4, "chkmcv6");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001255
Frank Blaschka4a71df52008-02-15 09:19:42 +01001256 if (!qeth_is_supported(card, IPA_IPV6))
1257 return ;
1258 in6_dev = in6_dev_get(card->dev);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001259 if (!in6_dev)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001260 return;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001261
Jiri Pirko0347af52013-01-03 22:48:58 +00001262 rcu_read_lock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01001263 read_lock_bh(&in6_dev->lock);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001264 qeth_l3_add_mc6_to_hash(card, in6_dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001265 qeth_l3_add_vlan_mc6(card);
1266 read_unlock_bh(&in6_dev->lock);
Jiri Pirko0347af52013-01-03 22:48:58 +00001267 rcu_read_unlock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01001268 in6_dev_put(in6_dev);
1269}
Frank Blaschka4a71df52008-02-15 09:19:42 +01001270
Patrick McHardy80d5c362013-04-19 02:04:28 +00001271static int qeth_l3_vlan_rx_add_vid(struct net_device *dev,
1272 __be16 proto, u16 vid)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001273{
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001274 struct qeth_card *card = dev->ml_priv;
1275
1276 set_bit(vid, card->active_vlans);
Jiri Pirko8e586132011-12-08 19:52:37 -05001277 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001278}
1279
Patrick McHardy80d5c362013-04-19 02:04:28 +00001280static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
1281 __be16 proto, u16 vid)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001282{
Heiko Carstens509e2562008-07-26 02:24:10 -07001283 struct qeth_card *card = dev->ml_priv;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001284
Carsten Otte847a50f2010-06-21 22:57:05 +00001285 QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001286
Ursula Braun8e98ac42009-03-24 20:57:18 +00001287 if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
Carsten Otte847a50f2010-06-21 22:57:05 +00001288 QETH_CARD_TEXT(card, 3, "kidREC");
Jiri Pirko8e586132011-12-08 19:52:37 -05001289 return 0;
Ursula Braun8e98ac42009-03-24 20:57:18 +00001290 }
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001291 clear_bit(vid, card->active_vlans);
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001292 qeth_l3_set_rx_mode(dev);
Jiri Pirko8e586132011-12-08 19:52:37 -05001293 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001294}
1295
Julian Wiedmannd7aa9d02017-09-18 21:18:21 +02001296static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
1297 struct qeth_hdr *hdr)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001298{
Frank Blaschka4a71df52008-02-15 09:19:42 +01001299 if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) {
Julian Wiedmann8d9183d2017-12-20 20:10:57 +01001300 u16 prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 :
1301 ETH_P_IP;
Julian Wiedmann99f0b852017-12-20 20:11:01 +01001302 unsigned char tg_addr[ETH_ALEN];
Julian Wiedmann8d9183d2017-12-20 20:10:57 +01001303
1304 skb_reset_network_header(skb);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001305 switch (hdr->hdr.l3.flags & QETH_HDR_CAST_MASK) {
1306 case QETH_CAST_MULTICAST:
Julian Wiedmannc0622042017-12-20 20:10:58 +01001307 if (prot == ETH_P_IP)
Julian Wiedmann8d9183d2017-12-20 20:10:57 +01001308 ip_eth_mc_map(ip_hdr(skb)->daddr, tg_addr);
Julian Wiedmannc0622042017-12-20 20:10:58 +01001309 else
1310 ipv6_eth_mc_map(&ipv6_hdr(skb)->daddr, tg_addr);
1311
Frank Blaschka4a71df52008-02-15 09:19:42 +01001312 card->stats.multicast++;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001313 break;
1314 case QETH_CAST_BROADCAST:
Julian Wiedmann99f0b852017-12-20 20:11:01 +01001315 ether_addr_copy(tg_addr, card->dev->broadcast);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001316 card->stats.multicast++;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001317 break;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001318 default:
Ursula Braun76b11f82010-01-11 02:50:50 +00001319 if (card->options.sniffer)
1320 skb->pkt_type = PACKET_OTHERHOST;
Julian Wiedmann99f0b852017-12-20 20:11:01 +01001321 ether_addr_copy(tg_addr, card->dev->dev_addr);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001322 }
Julian Wiedmann04f67392018-03-09 18:12:58 +01001323
Ursula Braunfe94e2e2009-01-04 17:34:52 -08001324 if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
1325 card->dev->header_ops->create(skb, card->dev, prot,
Julian Wiedmanna8433832017-12-20 20:11:06 +01001326 tg_addr, &hdr->hdr.l3.next_hop.rx.src_mac,
Julian Wiedmannf0ea8bf2018-03-09 18:12:56 +01001327 skb->len);
Ursula Braunfe94e2e2009-01-04 17:34:52 -08001328 else
1329 card->dev->header_ops->create(skb, card->dev, prot,
Julian Wiedmannf0ea8bf2018-03-09 18:12:56 +01001330 tg_addr, "FAKELL", skb->len);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001331 }
1332
Paul Gortmaker1abd2292012-05-10 15:50:52 -04001333 skb->protocol = eth_type_trans(skb, card->dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001334
Julian Wiedmannd7aa9d02017-09-18 21:18:21 +02001335 /* copy VLAN tag from hdr into skb */
1336 if (!card->options.sniffer &&
1337 (hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_VLAN_FRAME |
1338 QETH_HDR_EXT_INCLUDE_VLAN_TAG))) {
1339 u16 tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ?
1340 hdr->hdr.l3.vlan_id :
Julian Wiedmanna8433832017-12-20 20:11:06 +01001341 hdr->hdr.l3.next_hop.rx.vlan_id;
Julian Wiedmannd7aa9d02017-09-18 21:18:21 +02001342 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001343 }
1344
Julian Wiedmann6195b932018-04-26 09:42:17 +02001345 qeth_rx_csum(card, skb, hdr->hdr.l3.ext_flags);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001346}
1347
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00001348static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
1349 int budget, int *done)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001350{
Julian Wiedmanncd11d112018-09-26 18:29:06 +02001351 struct net_device *dev = card->dev;
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00001352 int work_done = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001353 struct sk_buff *skb;
1354 struct qeth_hdr *hdr;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001355 unsigned int len;
Frank Blaschkab3332932011-08-08 01:33:59 +00001356 __u16 magic;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001357
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00001358 *done = 0;
Stefan Raspl18af5c12012-11-19 02:46:50 +00001359 WARN_ON_ONCE(!budget);
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00001360 while (budget) {
1361 skb = qeth_core_get_next_skb(card,
Frank Blaschkab3332932011-08-08 01:33:59 +00001362 &card->qdio.in_q->bufs[card->rx.b_index],
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00001363 &card->rx.b_element, &card->rx.e_offset, &hdr);
1364 if (!skb) {
1365 *done = 1;
1366 break;
1367 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001368 switch (hdr->hdr.l3.id) {
1369 case QETH_HEADER_TYPE_LAYER3:
Frank Blaschkab3332932011-08-08 01:33:59 +00001370 magic = *(__u16 *)skb->data;
1371 if ((card->info.type == QETH_CARD_TYPE_IQD) &&
1372 (magic == ETH_P_AF_IUCV)) {
Frank Blaschkab3332932011-08-08 01:33:59 +00001373 len = skb->len;
Julian Wiedmanncd11d112018-09-26 18:29:06 +02001374 dev_hard_header(skb, dev, ETH_P_AF_IUCV,
1375 dev->dev_addr, "FAKELL", len);
1376 skb->protocol = eth_type_trans(skb, dev);
Frank Blaschkab3332932011-08-08 01:33:59 +00001377 netif_receive_skb(skb);
1378 } else {
Julian Wiedmannd7aa9d02017-09-18 21:18:21 +02001379 qeth_l3_rebuild_skb(card, skb, hdr);
Frank Blaschkab3332932011-08-08 01:33:59 +00001380 len = skb->len;
Frank Blaschkab3332932011-08-08 01:33:59 +00001381 napi_gro_receive(&card->napi, skb);
1382 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001383 break;
Ursula Braun76b11f82010-01-11 02:50:50 +00001384 case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */
Ursula Braun76b11f82010-01-11 02:50:50 +00001385 skb->protocol = eth_type_trans(skb, skb->dev);
Ursula Braun76b11f82010-01-11 02:50:50 +00001386 len = skb->len;
1387 netif_receive_skb(skb);
1388 break;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001389 default:
1390 dev_kfree_skb_any(skb);
Carsten Otte847a50f2010-06-21 22:57:05 +00001391 QETH_CARD_TEXT(card, 3, "inbunkno");
Julian Wiedmann0ac14872018-09-12 15:31:35 +02001392 QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr));
Frank Blaschka4a71df52008-02-15 09:19:42 +01001393 continue;
1394 }
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00001395 work_done++;
1396 budget--;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001397 card->stats.rx_packets++;
1398 card->stats.rx_bytes += len;
1399 }
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00001400 return work_done;
1401}
1402
Peter Senna Tschudinb2f4de82015-08-04 17:11:47 +02001403static void qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001404{
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02001405 QETH_DBF_TEXT(SETUP, 2, "stopcard");
1406 QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
Frank Blaschka4a71df52008-02-15 09:19:42 +01001407
1408 qeth_set_allowed_threads(card, 0, 1);
Ursula Braun76b11f82010-01-11 02:50:50 +00001409 if (card->options.sniffer &&
1410 (card->info.promisc_mode == SET_PROMISC_MODE_ON))
1411 qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001412 if (card->read.state == CH_STATE_UP &&
1413 card->write.state == CH_STATE_UP &&
1414 (card->state == CARD_STATE_UP)) {
1415 if (recovery_mode)
1416 qeth_l3_stop(card->dev);
Frank Blaschka8af7c5a2008-04-24 10:15:25 +02001417 else {
Ursula Braun869da902010-03-08 20:36:56 +00001418 rtnl_lock();
1419 dev_close(card->dev);
1420 rtnl_unlock();
Frank Blaschka8af7c5a2008-04-24 10:15:25 +02001421 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001422 card->state = CARD_STATE_SOFTSETUP;
1423 }
1424 if (card->state == CARD_STATE_SOFTSETUP) {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001425 qeth_l3_clear_ip_htable(card, 1);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001426 qeth_clear_ipacmd_list(card);
1427 card->state = CARD_STATE_HARDSETUP;
1428 }
1429 if (card->state == CARD_STATE_HARDSETUP) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001430 qeth_qdio_clear_card(card, 0);
1431 qeth_clear_qdio_buffers(card);
1432 qeth_clear_working_pool_list(card);
1433 card->state = CARD_STATE_DOWN;
1434 }
1435 if (card->state == CARD_STATE_DOWN) {
1436 qeth_clear_cmd_buffers(&card->read);
1437 qeth_clear_cmd_buffers(&card->write);
1438 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001439}
1440
Ursula Braun76b11f82010-01-11 02:50:50 +00001441/*
1442 * test for and Switch promiscuous mode (on or off)
1443 * either for guestlan or HiperSocket Sniffer
1444 */
1445static void
1446qeth_l3_handle_promisc_mode(struct qeth_card *card)
1447{
1448 struct net_device *dev = card->dev;
1449
1450 if (((dev->flags & IFF_PROMISC) &&
1451 (card->info.promisc_mode == SET_PROMISC_MODE_ON)) ||
1452 (!(dev->flags & IFF_PROMISC) &&
1453 (card->info.promisc_mode == SET_PROMISC_MODE_OFF)))
1454 return;
1455
1456 if (card->info.guestlan) { /* Guestlan trace */
1457 if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
1458 qeth_setadp_promisc_mode(card);
1459 } else if (card->options.sniffer && /* HiperSockets trace */
1460 qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
1461 if (dev->flags & IFF_PROMISC) {
Carsten Otte847a50f2010-06-21 22:57:05 +00001462 QETH_CARD_TEXT(card, 3, "+promisc");
Ursula Braun76b11f82010-01-11 02:50:50 +00001463 qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE);
1464 } else {
Carsten Otte847a50f2010-06-21 22:57:05 +00001465 QETH_CARD_TEXT(card, 3, "-promisc");
Ursula Braun76b11f82010-01-11 02:50:50 +00001466 qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
1467 }
1468 }
1469}
1470
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001471static void qeth_l3_set_rx_mode(struct net_device *dev)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001472{
Heiko Carstens509e2562008-07-26 02:24:10 -07001473 struct qeth_card *card = dev->ml_priv;
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001474 struct qeth_ipaddr *addr;
1475 struct hlist_node *tmp;
1476 int i, rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001477
Carsten Otte847a50f2010-06-21 22:57:05 +00001478 QETH_CARD_TEXT(card, 3, "setmulti");
Ursula Braun8e98ac42009-03-24 20:57:18 +00001479 if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
1480 (card->state != CARD_STATE_UP))
1481 return;
Ursula Braun76b11f82010-01-11 02:50:50 +00001482 if (!card->options.sniffer) {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001483 spin_lock_bh(&card->mclock);
1484
Ursula Braun76b11f82010-01-11 02:50:50 +00001485 qeth_l3_add_multicast_ipv4(card);
Ursula Braun76b11f82010-01-11 02:50:50 +00001486 qeth_l3_add_multicast_ipv6(card);
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001487
1488 hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
1489 switch (addr->disp_flag) {
1490 case QETH_DISP_ADDR_DELETE:
1491 rc = qeth_l3_deregister_addr_entry(card, addr);
1492 if (!rc || rc == IPA_RC_MC_ADDR_NOT_FOUND) {
1493 hash_del(&addr->hnode);
1494 kfree(addr);
1495 }
1496 break;
1497 case QETH_DISP_ADDR_ADD:
1498 rc = qeth_l3_register_addr_entry(card, addr);
1499 if (rc && rc != IPA_RC_LAN_OFFLINE) {
1500 hash_del(&addr->hnode);
1501 kfree(addr);
1502 break;
1503 }
1504 addr->ref_counter = 1;
1505 /* fall through */
1506 default:
1507 /* for next call to set_rx_mode(): */
1508 addr->disp_flag = QETH_DISP_ADDR_DELETE;
1509 }
1510 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001511
1512 spin_unlock_bh(&card->mclock);
1513
Ursula Braun76b11f82010-01-11 02:50:50 +00001514 if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
1515 return;
1516 }
1517 qeth_l3_handle_promisc_mode(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001518}
1519
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001520static int qeth_l3_arp_makerc(int rc)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001521{
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001522 switch (rc) {
1523 case IPA_RC_SUCCESS:
1524 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001525 case QETH_IPA_ARP_RC_NOTSUPP:
Frank Blaschka4a71df52008-02-15 09:19:42 +01001526 case QETH_IPA_ARP_RC_Q_NOTSUPP:
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001527 return -EOPNOTSUPP;
1528 case QETH_IPA_ARP_RC_OUT_OF_RANGE:
1529 return -EINVAL;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001530 case QETH_IPA_ARP_RC_Q_NO_DATA:
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001531 return -ENOENT;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001532 default:
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001533 return -EIO;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001534 }
1535}
1536
1537static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
1538{
Frank Blaschka4a71df52008-02-15 09:19:42 +01001539 int rc;
1540
Carsten Otte847a50f2010-06-21 22:57:05 +00001541 QETH_CARD_TEXT(card, 3, "arpstnoe");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001542
1543 /*
1544 * currently GuestLAN only supports the ARP assist function
1545 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_SET_NO_ENTRIES;
1546 * thus we say EOPNOTSUPP for this ARP function
1547 */
1548 if (card->info.guestlan)
1549 return -EOPNOTSUPP;
1550 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001551 return -EOPNOTSUPP;
1552 }
Thomas Richter4d7def22015-09-18 16:06:51 +02001553 rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
Frank Blaschka4a71df52008-02-15 09:19:42 +01001554 IPA_CMD_ASS_ARP_SET_NO_ENTRIES,
1555 no_entries);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001556 if (rc)
1557 QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on device %x: %#x\n",
1558 CARD_DEVID(card), rc);
1559 return qeth_l3_arp_makerc(rc);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001560}
1561
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001562static __u32 get_arp_entry_size(struct qeth_card *card,
1563 struct qeth_arp_query_data *qdata,
1564 struct qeth_arp_entrytype *type, __u8 strip_entries)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001565{
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001566 __u32 rc;
1567 __u8 is_hsi;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001568
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001569 is_hsi = qdata->reply_bits == 5;
1570 if (type->ip == QETHARP_IP_ADDR_V4) {
1571 QETH_CARD_TEXT(card, 4, "arpev4");
1572 if (strip_entries) {
1573 rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5_short) :
1574 sizeof(struct qeth_arp_qi_entry7_short);
1575 } else {
1576 rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5) :
1577 sizeof(struct qeth_arp_qi_entry7);
1578 }
1579 } else if (type->ip == QETHARP_IP_ADDR_V6) {
1580 QETH_CARD_TEXT(card, 4, "arpev6");
1581 if (strip_entries) {
1582 rc = is_hsi ?
1583 sizeof(struct qeth_arp_qi_entry5_short_ipv6) :
1584 sizeof(struct qeth_arp_qi_entry7_short_ipv6);
1585 } else {
1586 rc = is_hsi ?
1587 sizeof(struct qeth_arp_qi_entry5_ipv6) :
1588 sizeof(struct qeth_arp_qi_entry7_ipv6);
1589 }
1590 } else {
1591 QETH_CARD_TEXT(card, 4, "arpinv");
1592 rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001593 }
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001594
1595 return rc;
1596}
1597
1598static int arpentry_matches_prot(struct qeth_arp_entrytype *type, __u16 prot)
1599{
1600 return (type->ip == QETHARP_IP_ADDR_V4 && prot == QETH_PROT_IPV4) ||
1601 (type->ip == QETHARP_IP_ADDR_V6 && prot == QETH_PROT_IPV6);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001602}
1603
1604static int qeth_l3_arp_query_cb(struct qeth_card *card,
1605 struct qeth_reply *reply, unsigned long data)
1606{
1607 struct qeth_ipa_cmd *cmd;
1608 struct qeth_arp_query_data *qdata;
1609 struct qeth_arp_query_info *qinfo;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001610 int i;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001611 int e;
1612 int entrybytes_done;
1613 int stripped_bytes;
1614 __u8 do_strip_entries;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001615
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001616 QETH_CARD_TEXT(card, 3, "arpquecb");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001617
1618 qinfo = (struct qeth_arp_query_info *) reply->param;
1619 cmd = (struct qeth_ipa_cmd *) data;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001620 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.prot_version);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001621 if (cmd->hdr.return_code) {
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001622 QETH_CARD_TEXT(card, 4, "arpcberr");
1623 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001624 return 0;
1625 }
1626 if (cmd->data.setassparms.hdr.return_code) {
1627 cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001628 QETH_CARD_TEXT(card, 4, "setaperr");
1629 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001630 return 0;
1631 }
1632 qdata = &cmd->data.setassparms.data.query_arp;
Carsten Otte847a50f2010-06-21 22:57:05 +00001633 QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001634
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001635 do_strip_entries = (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) > 0;
1636 stripped_bytes = do_strip_entries ? QETH_QARP_MEDIASPECIFIC_BYTES : 0;
1637 entrybytes_done = 0;
1638 for (e = 0; e < qdata->no_entries; ++e) {
1639 char *cur_entry;
1640 __u32 esize;
1641 struct qeth_arp_entrytype *etype;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001642
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001643 cur_entry = &qdata->data + entrybytes_done;
1644 etype = &((struct qeth_arp_qi_entry5 *) cur_entry)->type;
1645 if (!arpentry_matches_prot(etype, cmd->hdr.prot_version)) {
1646 QETH_CARD_TEXT(card, 4, "pmis");
1647 QETH_CARD_TEXT_(card, 4, "%i", etype->ip);
1648 break;
1649 }
1650 esize = get_arp_entry_size(card, qdata, etype,
1651 do_strip_entries);
1652 QETH_CARD_TEXT_(card, 5, "esz%i", esize);
1653 if (!esize)
1654 break;
1655
1656 if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
1657 QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
Ursula Braune0a81142012-03-07 02:06:28 +00001658 cmd->hdr.return_code = IPA_RC_ENOMEM;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001659 goto out_error;
1660 }
1661
1662 memcpy(qinfo->udata + qinfo->udata_offset,
1663 &qdata->data + entrybytes_done + stripped_bytes,
1664 esize);
1665 entrybytes_done += esize + stripped_bytes;
1666 qinfo->udata_offset += esize;
1667 ++qinfo->no_entries;
1668 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001669 /* check if all replies received ... */
1670 if (cmd->data.setassparms.hdr.seq_no <
1671 cmd->data.setassparms.hdr.number_of_replies)
1672 return 1;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001673 QETH_CARD_TEXT_(card, 4, "nove%i", qinfo->no_entries);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001674 memcpy(qinfo->udata, &qinfo->no_entries, 4);
1675 /* keep STRIP_ENTRIES flag so the user program can distinguish
1676 * stripped entries from normal ones */
1677 if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
1678 qdata->reply_bits |= QETH_QARP_STRIP_ENTRIES;
1679 memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001680 QETH_CARD_TEXT_(card, 4, "rc%i", 0);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001681 return 0;
1682out_error:
1683 i = 0;
1684 memcpy(qinfo->udata, &i, 4);
1685 return 0;
1686}
1687
1688static int qeth_l3_send_ipa_arp_cmd(struct qeth_card *card,
1689 struct qeth_cmd_buffer *iob, int len,
1690 int (*reply_cb)(struct qeth_card *, struct qeth_reply *,
1691 unsigned long),
1692 void *reply_param)
1693{
Carsten Otte847a50f2010-06-21 22:57:05 +00001694 QETH_CARD_TEXT(card, 4, "sendarp");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001695
1696 memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
1697 memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
1698 &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
1699 return qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob,
1700 reply_cb, reply_param);
1701}
1702
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001703static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
1704 enum qeth_prot_versions prot,
1705 struct qeth_arp_query_info *qinfo)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001706{
1707 struct qeth_cmd_buffer *iob;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001708 struct qeth_ipa_cmd *cmd;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001709 int rc;
1710
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001711 QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot);
1712
Thomas Richterb475e312015-12-11 12:27:54 +01001713 iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
1714 IPA_CMD_ASS_ARP_QUERY_INFO,
1715 sizeof(struct qeth_arp_query_data)
1716 - sizeof(char),
1717 prot);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001718 if (!iob)
1719 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +01001720 cmd = __ipa_cmd(iob);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001721 cmd->data.setassparms.data.query_arp.request_bits = 0x000F;
1722 cmd->data.setassparms.data.query_arp.reply_bits = 0;
1723 cmd->data.setassparms.data.query_arp.no_entries = 0;
1724 rc = qeth_l3_send_ipa_arp_cmd(card, iob,
1725 QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN,
1726 qeth_l3_arp_query_cb, (void *)qinfo);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001727 if (rc)
1728 QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n",
1729 CARD_DEVID(card), rc);
1730 return qeth_l3_arp_makerc(rc);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001731}
1732
1733static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
1734{
1735 struct qeth_arp_query_info qinfo = {0, };
1736 int rc;
1737
Carsten Otte847a50f2010-06-21 22:57:05 +00001738 QETH_CARD_TEXT(card, 3, "arpquery");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001739
1740 if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/
1741 IPA_ARP_PROCESSING)) {
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001742 QETH_CARD_TEXT(card, 3, "arpqnsup");
1743 rc = -EOPNOTSUPP;
1744 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001745 }
1746 /* get size of userspace buffer and mask_bits -> 6 bytes */
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001747 if (copy_from_user(&qinfo, udata, 6)) {
1748 rc = -EFAULT;
1749 goto out;
1750 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001751 qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001752 if (!qinfo.udata) {
1753 rc = -ENOMEM;
1754 goto out;
1755 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001756 qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001757 rc = qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV4, &qinfo);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001758 if (rc) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001759 if (copy_to_user(udata, qinfo.udata, 4))
1760 rc = -EFAULT;
Sebastian Ott77a83ed2016-06-16 16:19:03 +02001761 goto free_and_out;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001762 }
Sebastian Ott77a83ed2016-06-16 16:19:03 +02001763 if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) {
1764 /* fails in case of GuestLAN QDIO mode */
1765 qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6, &qinfo);
1766 }
Sebastian Ott77a83ed2016-06-16 16:19:03 +02001767 if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) {
1768 QETH_CARD_TEXT(card, 4, "qactf");
1769 rc = -EFAULT;
1770 goto free_and_out;
1771 }
1772 QETH_CARD_TEXT(card, 4, "qacts");
1773
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001774free_and_out:
Frank Blaschka4a71df52008-02-15 09:19:42 +01001775 kfree(qinfo.udata);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001776out:
Frank Blaschka4a71df52008-02-15 09:19:42 +01001777 return rc;
1778}
1779
1780static int qeth_l3_arp_add_entry(struct qeth_card *card,
1781 struct qeth_arp_cache_entry *entry)
1782{
1783 struct qeth_cmd_buffer *iob;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001784 int rc;
1785
Carsten Otte847a50f2010-06-21 22:57:05 +00001786 QETH_CARD_TEXT(card, 3, "arpadent");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001787
1788 /*
1789 * currently GuestLAN only supports the ARP assist function
1790 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_ADD_ENTRY;
1791 * thus we say EOPNOTSUPP for this ARP function
1792 */
1793 if (card->info.guestlan)
1794 return -EOPNOTSUPP;
1795 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001796 return -EOPNOTSUPP;
1797 }
1798
Thomas Richterb475e312015-12-11 12:27:54 +01001799 iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
Frank Blaschka4a71df52008-02-15 09:19:42 +01001800 IPA_CMD_ASS_ARP_ADD_ENTRY,
1801 sizeof(struct qeth_arp_cache_entry),
1802 QETH_PROT_IPV4);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001803 if (!iob)
1804 return -ENOMEM;
Thomas Richter4d7def22015-09-18 16:06:51 +02001805 rc = qeth_send_setassparms(card, iob,
Frank Blaschka4a71df52008-02-15 09:19:42 +01001806 sizeof(struct qeth_arp_cache_entry),
1807 (unsigned long) entry,
Thomas Richter8f43fb02016-06-16 16:18:59 +02001808 qeth_setassparms_cb, NULL);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001809 if (rc)
1810 QETH_DBF_MESSAGE(2, "Could not add ARP entry on device %x: %#x\n",
1811 CARD_DEVID(card), rc);
1812 return qeth_l3_arp_makerc(rc);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001813}
1814
1815static int qeth_l3_arp_remove_entry(struct qeth_card *card,
1816 struct qeth_arp_cache_entry *entry)
1817{
1818 struct qeth_cmd_buffer *iob;
1819 char buf[16] = {0, };
Frank Blaschka4a71df52008-02-15 09:19:42 +01001820 int rc;
1821
Carsten Otte847a50f2010-06-21 22:57:05 +00001822 QETH_CARD_TEXT(card, 3, "arprment");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001823
1824 /*
1825 * currently GuestLAN only supports the ARP assist function
1826 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_REMOVE_ENTRY;
1827 * thus we say EOPNOTSUPP for this ARP function
1828 */
1829 if (card->info.guestlan)
1830 return -EOPNOTSUPP;
1831 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001832 return -EOPNOTSUPP;
1833 }
1834 memcpy(buf, entry, 12);
Thomas Richterb475e312015-12-11 12:27:54 +01001835 iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
Frank Blaschka4a71df52008-02-15 09:19:42 +01001836 IPA_CMD_ASS_ARP_REMOVE_ENTRY,
1837 12,
1838 QETH_PROT_IPV4);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001839 if (!iob)
1840 return -ENOMEM;
Thomas Richter4d7def22015-09-18 16:06:51 +02001841 rc = qeth_send_setassparms(card, iob,
Frank Blaschka4a71df52008-02-15 09:19:42 +01001842 12, (unsigned long)buf,
Thomas Richter8f43fb02016-06-16 16:18:59 +02001843 qeth_setassparms_cb, NULL);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001844 if (rc)
1845 QETH_DBF_MESSAGE(2, "Could not delete ARP entry on device %x: %#x\n",
1846 CARD_DEVID(card), rc);
1847 return qeth_l3_arp_makerc(rc);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001848}
1849
1850static int qeth_l3_arp_flush_cache(struct qeth_card *card)
1851{
1852 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001853
Carsten Otte847a50f2010-06-21 22:57:05 +00001854 QETH_CARD_TEXT(card, 3, "arpflush");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001855
1856 /*
1857 * currently GuestLAN only supports the ARP assist function
1858 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_FLUSH_CACHE;
1859 * thus we say EOPNOTSUPP for this ARP function
1860 */
1861 if (card->info.guestlan || (card->info.type == QETH_CARD_TYPE_IQD))
1862 return -EOPNOTSUPP;
1863 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001864 return -EOPNOTSUPP;
1865 }
Thomas Richter4d7def22015-09-18 16:06:51 +02001866 rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
Frank Blaschka4a71df52008-02-15 09:19:42 +01001867 IPA_CMD_ASS_ARP_FLUSH_CACHE, 0);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001868 if (rc)
1869 QETH_DBF_MESSAGE(2, "Could not flush ARP cache on device %x: %#x\n",
1870 CARD_DEVID(card), rc);
1871 return qeth_l3_arp_makerc(rc);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001872}
1873
1874static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
1875{
Heiko Carstens509e2562008-07-26 02:24:10 -07001876 struct qeth_card *card = dev->ml_priv;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001877 struct qeth_arp_cache_entry arp_entry;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001878 int rc = 0;
1879
Frank Blaschka4a71df52008-02-15 09:19:42 +01001880 switch (cmd) {
1881 case SIOC_QETH_ARP_SET_NO_ENTRIES:
1882 if (!capable(CAP_NET_ADMIN)) {
1883 rc = -EPERM;
1884 break;
1885 }
1886 rc = qeth_l3_arp_set_no_entries(card, rq->ifr_ifru.ifru_ivalue);
1887 break;
1888 case SIOC_QETH_ARP_QUERY_INFO:
1889 if (!capable(CAP_NET_ADMIN)) {
1890 rc = -EPERM;
1891 break;
1892 }
1893 rc = qeth_l3_arp_query(card, rq->ifr_ifru.ifru_data);
1894 break;
1895 case SIOC_QETH_ARP_ADD_ENTRY:
1896 if (!capable(CAP_NET_ADMIN)) {
1897 rc = -EPERM;
1898 break;
1899 }
1900 if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
1901 sizeof(struct qeth_arp_cache_entry)))
1902 rc = -EFAULT;
1903 else
1904 rc = qeth_l3_arp_add_entry(card, &arp_entry);
1905 break;
1906 case SIOC_QETH_ARP_REMOVE_ENTRY:
1907 if (!capable(CAP_NET_ADMIN)) {
1908 rc = -EPERM;
1909 break;
1910 }
1911 if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
1912 sizeof(struct qeth_arp_cache_entry)))
1913 rc = -EFAULT;
1914 else
1915 rc = qeth_l3_arp_remove_entry(card, &arp_entry);
1916 break;
1917 case SIOC_QETH_ARP_FLUSH_CACHE:
1918 if (!capable(CAP_NET_ADMIN)) {
1919 rc = -EPERM;
1920 break;
1921 }
1922 rc = qeth_l3_arp_flush_cache(card);
1923 break;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001924 default:
1925 rc = -EOPNOTSUPP;
1926 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001927 return rc;
1928}
1929
Julian Wiedmann1f979122017-12-20 20:11:04 +01001930static int qeth_l3_get_cast_type(struct sk_buff *skb)
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001931{
David S. Miller69cce1d2011-07-17 23:09:49 -07001932 struct neighbour *n = NULL;
1933 struct dst_entry *dst;
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001934
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001935 rcu_read_lock();
David S. Miller69cce1d2011-07-17 23:09:49 -07001936 dst = skb_dst(skb);
1937 if (dst)
David S. Miller24db1ba2012-07-02 22:02:33 -07001938 n = dst_neigh_lookup_skb(dst, skb);
David S. Miller69cce1d2011-07-17 23:09:49 -07001939 if (n) {
Julian Wiedmann1f979122017-12-20 20:11:04 +01001940 int cast_type = n->type;
1941
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001942 rcu_read_unlock();
David S. Miller24db1ba2012-07-02 22:02:33 -07001943 neigh_release(n);
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001944 if ((cast_type == RTN_BROADCAST) ||
1945 (cast_type == RTN_MULTICAST) ||
1946 (cast_type == RTN_ANYCAST))
1947 return cast_type;
Julian Wiedmann86c0cdb2018-07-11 17:42:41 +02001948 return RTN_UNICAST;
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001949 }
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001950 rcu_read_unlock();
1951
Julian Wiedmann1f979122017-12-20 20:11:04 +01001952 /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001953 switch (qeth_get_ip_version(skb)) {
1954 case 4:
Julian Wiedmann1f979122017-12-20 20:11:04 +01001955 return ipv4_is_multicast(ip_hdr(skb)->daddr) ?
Julian Wiedmann86c0cdb2018-07-11 17:42:41 +02001956 RTN_MULTICAST : RTN_UNICAST;
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001957 case 6:
1958 return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
1959 RTN_MULTICAST : RTN_UNICAST;
1960 default:
1961 /* ... and MAC address */
1962 if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest,
1963 skb->dev->broadcast))
1964 return RTN_BROADCAST;
1965 if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
1966 return RTN_MULTICAST;
1967 /* default to unicast */
1968 return RTN_UNICAST;
1969 }
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001970}
1971
Julian Wiedmanna647a022018-07-11 17:42:46 +02001972static void qeth_l3_fill_af_iucv_hdr(struct qeth_hdr *hdr, struct sk_buff *skb,
1973 unsigned int data_len)
Frank Blaschkab3332932011-08-08 01:33:59 +00001974{
1975 char daddr[16];
Frank Blaschkab3332932011-08-08 01:33:59 +00001976
Frank Blaschkab3332932011-08-08 01:33:59 +00001977 hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
Julian Wiedmanna647a022018-07-11 17:42:46 +02001978 hdr->hdr.l3.length = data_len;
Frank Blaschkab3332932011-08-08 01:33:59 +00001979 hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
Julian Wiedmannacd97762017-03-23 14:55:09 +01001980
Frank Blaschkab3332932011-08-08 01:33:59 +00001981 memset(daddr, 0, sizeof(daddr));
1982 daddr[0] = 0xfe;
1983 daddr[1] = 0x80;
Julian Wiedmanncd11d112018-09-26 18:29:06 +02001984 memcpy(&daddr[8], iucv_trans_hdr(skb)->destUserID, 8);
Julian Wiedmanna8433832017-12-20 20:11:06 +01001985 memcpy(hdr->hdr.l3.next_hop.ipv6_addr, daddr, 16);
Frank Blaschkab3332932011-08-08 01:33:59 +00001986}
1987
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001988static u8 qeth_l3_cast_type_to_flag(int cast_type)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001989{
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001990 if (cast_type == RTN_MULTICAST)
1991 return QETH_CAST_MULTICAST;
1992 if (cast_type == RTN_ANYCAST)
1993 return QETH_CAST_ANYCAST;
1994 if (cast_type == RTN_BROADCAST)
1995 return QETH_CAST_BROADCAST;
1996 return QETH_CAST_UNICAST;
1997}
David S. Miller69cce1d2011-07-17 23:09:49 -07001998
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001999static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
Julian Wiedmannf6c13142017-12-20 20:11:08 +01002000 struct sk_buff *skb, int ipv, int cast_type,
2001 unsigned int data_len)
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002002{
Julian Wiedmannf13ade12018-09-17 17:35:56 +02002003 struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
2004
Julian Wiedmannf6c13142017-12-20 20:11:08 +01002005 hdr->hdr.l3.length = data_len;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002006
Julian Wiedmanne517b642018-09-17 17:36:02 +02002007 if (skb_is_gso(skb)) {
Julian Wiedmann0aef8392018-10-12 17:27:15 +02002008 hdr->hdr.l3.id = QETH_HEADER_TYPE_L3_TSO;
Julian Wiedmanne517b642018-09-17 17:36:02 +02002009 } else {
2010 hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
2011 if (skb->ip_summed == CHECKSUM_PARTIAL) {
2012 qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv);
2013 /* some HW requires combined L3+L4 csum offload: */
2014 if (ipv == 4)
2015 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ;
2016 if (card->options.performance_stats)
2017 card->perf_stats.tx_csum++;
2018 }
2019 }
2020
Julian Wiedmannf13ade12018-09-17 17:35:56 +02002021 if (ipv == 4 || IS_IQD(card)) {
2022 /* NETIF_F_HW_VLAN_CTAG_TX */
2023 if (skb_vlan_tag_present(skb)) {
2024 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_VLAN_FRAME;
2025 hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
2026 }
2027 } else if (veth->h_vlan_proto == htons(ETH_P_8021Q)) {
2028 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_INCLUDE_VLAN_TAG;
2029 hdr->hdr.l3.vlan_id = ntohs(veth->h_vlan_TCI);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002030 }
2031
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002032 /* OSA only: */
2033 if (!ipv) {
2034 hdr->hdr.l3.flags = QETH_HDR_PASSTHRU;
2035 if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest,
2036 skb->dev->broadcast))
2037 hdr->hdr.l3.flags |= QETH_CAST_BROADCAST;
2038 else
2039 hdr->hdr.l3.flags |= (cast_type == RTN_MULTICAST) ?
2040 QETH_CAST_MULTICAST : QETH_CAST_UNICAST;
2041 return;
2042 }
Frank Blaschka1d36cb42011-11-15 02:31:15 +00002043
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002044 hdr->hdr.l3.flags = qeth_l3_cast_type_to_flag(cast_type);
Frank Blaschka1d36cb42011-11-15 02:31:15 +00002045 rcu_read_lock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002046 if (ipv == 4) {
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002047 struct rtable *rt = skb_rtable(skb);
David Miller87e75972012-02-01 10:49:17 +00002048
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002049 *((__be32 *) &hdr->hdr.l3.next_hop.ipv4.addr) = (rt) ?
2050 rt_nexthop(rt, ip_hdr(skb)->daddr) :
2051 ip_hdr(skb)->daddr;
2052 } else {
2053 /* IPv6 */
2054 const struct rt6_info *rt = skb_rt6_info(skb);
2055 const struct in6_addr *next_hop;
David Miller87e75972012-02-01 10:49:17 +00002056
Julian Wiedmannec2c6722017-08-07 13:28:39 +02002057 if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002058 next_hop = &rt->rt6i_gateway;
2059 else
2060 next_hop = &ipv6_hdr(skb)->daddr;
2061 memcpy(hdr->hdr.l3.next_hop.ipv6_addr, next_hop, 16);
David Miller87e75972012-02-01 10:49:17 +00002062
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002063 hdr->hdr.l3.flags |= QETH_HDR_IPV6;
2064 if (card->info.type != QETH_CARD_TYPE_IQD)
2065 hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002066 }
Frank Blaschka1d36cb42011-11-15 02:31:15 +00002067 rcu_read_unlock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002068}
2069
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02002070static void qeth_l3_fixup_headers(struct sk_buff *skb)
2071{
2072 struct iphdr *iph = ip_hdr(skb);
2073
2074 /* this is safe, IPv6 traffic takes a different path */
2075 if (skb->ip_summed == CHECKSUM_PARTIAL)
2076 iph->check = 0;
Julian Wiedmanne517b642018-09-17 17:36:02 +02002077 if (skb_is_gso(skb)) {
2078 iph->tot_len = 0;
2079 tcp_hdr(skb)->check = ~tcp_v4_check(0, iph->saddr,
2080 iph->daddr, 0);
2081 }
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02002082}
2083
Julian Wiedmann356156b2018-09-17 17:36:03 +02002084static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
2085 struct qeth_qdio_out_q *queue, int ipv, int cast_type)
Julian Wiedmanna647a022018-07-11 17:42:46 +02002086{
Julian Wiedmanne517b642018-09-17 17:36:02 +02002087 unsigned int hw_hdr_len, proto_len, frame_len, elements;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002088 unsigned char eth_hdr[ETH_HLEN];
Julian Wiedmanne517b642018-09-17 17:36:02 +02002089 bool is_tso = skb_is_gso(skb);
2090 unsigned int data_offset = 0;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002091 struct qeth_hdr *hdr = NULL;
2092 unsigned int hd_len = 0;
Julian Wiedmannba86ceee2018-07-19 12:43:56 +02002093 int push_len, rc;
Julian Wiedmannd2a274b2018-07-19 12:43:55 +02002094 bool is_sg;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002095
Julian Wiedmanne517b642018-09-17 17:36:02 +02002096 if (is_tso) {
2097 hw_hdr_len = sizeof(struct qeth_hdr_tso);
2098 proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb) -
2099 ETH_HLEN;
2100 } else {
2101 hw_hdr_len = sizeof(struct qeth_hdr);
2102 proto_len = 0;
2103 }
2104
Julian Wiedmanna647a022018-07-11 17:42:46 +02002105 /* re-use the L2 header area for the HW header: */
2106 rc = skb_cow_head(skb, hw_hdr_len - ETH_HLEN);
2107 if (rc)
2108 return rc;
2109 skb_copy_from_linear_data(skb, eth_hdr, ETH_HLEN);
2110 skb_pull(skb, ETH_HLEN);
2111 frame_len = skb->len;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002112
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02002113 qeth_l3_fixup_headers(skb);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002114 push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len,
Julian Wiedmanna7c2f4a2018-07-19 12:43:57 +02002115 &elements);
Julian Wiedmanna647a022018-07-11 17:42:46 +02002116 if (push_len < 0)
2117 return push_len;
Julian Wiedmanne517b642018-09-17 17:36:02 +02002118 if (is_tso || !push_len) {
2119 /* HW header needs its own buffer element. */
2120 hd_len = hw_hdr_len + proto_len;
2121 data_offset = push_len + proto_len;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002122 }
Julian Wiedmanne517b642018-09-17 17:36:02 +02002123 memset(hdr, 0, hw_hdr_len);
Julian Wiedmanna647a022018-07-11 17:42:46 +02002124
Julian Wiedmanne517b642018-09-17 17:36:02 +02002125 if (skb->protocol == htons(ETH_P_AF_IUCV)) {
Julian Wiedmanna647a022018-07-11 17:42:46 +02002126 qeth_l3_fill_af_iucv_hdr(hdr, skb, frame_len);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002127 } else {
Julian Wiedmanna647a022018-07-11 17:42:46 +02002128 qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002129 if (is_tso)
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002130 qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr,
2131 frame_len - proto_len, skb,
2132 proto_len);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002133 }
Julian Wiedmanna647a022018-07-11 17:42:46 +02002134
Julian Wiedmannd2a274b2018-07-19 12:43:55 +02002135 is_sg = skb_is_nonlinear(skb);
Julian Wiedmannfb321f22018-07-11 17:42:47 +02002136 if (IS_IQD(card)) {
Julian Wiedmanne517b642018-09-17 17:36:02 +02002137 rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset,
2138 hd_len);
Julian Wiedmannfb321f22018-07-11 17:42:47 +02002139 } else {
2140 /* TODO: drop skb_orphan() once TX completion is fast enough */
2141 skb_orphan(skb);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002142 rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset,
2143 hd_len, elements);
Julian Wiedmannfb321f22018-07-11 17:42:47 +02002144 }
Julian Wiedmannba86ceee2018-07-19 12:43:56 +02002145
Julian Wiedmanna647a022018-07-11 17:42:46 +02002146 if (!rc) {
Julian Wiedmannd2a274b2018-07-19 12:43:55 +02002147 if (card->options.performance_stats) {
2148 card->perf_stats.buf_elements_sent += elements;
2149 if (is_sg)
2150 card->perf_stats.sg_skbs_sent++;
Julian Wiedmanne517b642018-09-17 17:36:02 +02002151 if (is_tso) {
2152 card->perf_stats.large_send_bytes += frame_len;
2153 card->perf_stats.large_send_cnt++;
2154 }
Julian Wiedmanna647a022018-07-11 17:42:46 +02002155 }
2156 } else {
2157 if (!push_len)
2158 kmem_cache_free(qeth_core_header_cache, hdr);
2159 if (rc == -EBUSY) {
2160 /* roll back to ETH header */
2161 skb_pull(skb, push_len);
2162 skb_push(skb, ETH_HLEN);
2163 skb_copy_to_linear_data(skb, eth_hdr, ETH_HLEN);
2164 }
2165 }
2166 return rc;
2167}
2168
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02002169static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
2170 struct net_device *dev)
2171{
2172 int cast_type = qeth_l3_get_cast_type(skb);
2173 struct qeth_card *card = dev->ml_priv;
2174 int ipv = qeth_get_ip_version(skb);
2175 struct qeth_qdio_out_q *queue;
2176 int tx_bytes = skb->len;
2177 int rc;
2178
2179 if (IS_IQD(card)) {
2180 if (card->options.sniffer)
2181 goto tx_drop;
2182 if ((card->options.cq != QETH_CQ_ENABLED && !ipv) ||
2183 (card->options.cq == QETH_CQ_ENABLED &&
2184 skb->protocol != htons(ETH_P_AF_IUCV)))
Frank Blaschka4a71df52008-02-15 09:19:42 +01002185 goto tx_drop;
2186 }
2187
Julian Wiedmann91cc98f2018-09-26 18:29:16 +02002188 if (card->state != CARD_STATE_UP) {
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02002189 card->stats.tx_carrier_errors++;
2190 goto tx_drop;
2191 }
2192
2193 if (cast_type == RTN_BROADCAST && !card->info.broadcast_capable)
2194 goto tx_drop;
2195
2196 queue = qeth_get_tx_queue(card, skb, ipv, cast_type);
2197
2198 if (card->options.performance_stats) {
2199 card->perf_stats.outbound_cnt++;
2200 card->perf_stats.outbound_start_time = qeth_get_micros();
2201 }
2202 netif_stop_queue(dev);
2203
Julian Wiedmann356156b2018-09-17 17:36:03 +02002204 if (ipv == 4 || IS_IQD(card))
Julian Wiedmanna647a022018-07-11 17:42:46 +02002205 rc = qeth_l3_xmit(card, skb, queue, ipv, cast_type);
Julian Wiedmannf13ade12018-09-17 17:35:56 +02002206 else
2207 rc = qeth_xmit(card, skb, queue, ipv, cast_type,
2208 qeth_l3_fill_header);
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02002209
2210 if (!rc) {
2211 card->stats.tx_packets++;
2212 card->stats.tx_bytes += tx_bytes;
2213 if (card->options.performance_stats)
2214 card->perf_stats.outbound_time += qeth_get_micros() -
2215 card->perf_stats.outbound_start_time;
2216 netif_wake_queue(dev);
2217 return NETDEV_TX_OK;
2218 } else if (rc == -EBUSY) {
2219 return NETDEV_TX_BUSY;
2220 } /* else fall through */
Frank Blaschka4a71df52008-02-15 09:19:42 +01002221
2222tx_drop:
2223 card->stats.tx_dropped++;
2224 card->stats.tx_errors++;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002225 dev_kfree_skb_any(skb);
Frank Blaschkad0ec0f52008-06-06 12:37:48 +02002226 netif_wake_queue(dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002227 return NETDEV_TX_OK;
2228}
2229
Ursula Braun39423442011-01-12 20:42:24 +00002230static int __qeth_l3_open(struct net_device *dev)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002231{
Heiko Carstens509e2562008-07-26 02:24:10 -07002232 struct qeth_card *card = dev->ml_priv;
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002233 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002234
Carsten Otte847a50f2010-06-21 22:57:05 +00002235 QETH_CARD_TEXT(card, 4, "qethopen");
Ursula Braun39423442011-01-12 20:42:24 +00002236 if (card->state == CARD_STATE_UP)
2237 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002238 if (card->state != CARD_STATE_SOFTSETUP)
2239 return -ENODEV;
2240 card->data.state = CH_STATE_UP;
2241 card->state = CARD_STATE_UP;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002242 netif_start_queue(dev);
2243
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002244 if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
2245 napi_enable(&card->napi);
Julian Wiedmann4d19db72018-09-17 17:36:06 +02002246 local_bh_disable();
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002247 napi_schedule(&card->napi);
Julian Wiedmann4d19db72018-09-17 17:36:06 +02002248 /* kick-start the NAPI softirq: */
2249 local_bh_enable();
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002250 } else
2251 rc = -EIO;
2252 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002253}
2254
Ursula Braun39423442011-01-12 20:42:24 +00002255static int qeth_l3_open(struct net_device *dev)
2256{
2257 struct qeth_card *card = dev->ml_priv;
2258
2259 QETH_CARD_TEXT(card, 5, "qethope_");
2260 if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
2261 QETH_CARD_TEXT(card, 3, "openREC");
2262 return -ERESTARTSYS;
2263 }
2264 return __qeth_l3_open(dev);
2265}
2266
Frank Blaschka4a71df52008-02-15 09:19:42 +01002267static int qeth_l3_stop(struct net_device *dev)
2268{
Heiko Carstens509e2562008-07-26 02:24:10 -07002269 struct qeth_card *card = dev->ml_priv;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002270
Carsten Otte847a50f2010-06-21 22:57:05 +00002271 QETH_CARD_TEXT(card, 4, "qethstop");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002272 netif_tx_disable(dev);
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002273 if (card->state == CARD_STATE_UP) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01002274 card->state = CARD_STATE_SOFTSETUP;
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002275 napi_disable(&card->napi);
2276 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002277 return 0;
2278}
2279
Stephen Hemminger0fc0b732009-09-02 01:03:33 -07002280static const struct ethtool_ops qeth_l3_ethtool_ops = {
Frank Blaschka4a71df52008-02-15 09:19:42 +01002281 .get_link = ethtool_op_get_link,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002282 .get_strings = qeth_core_get_strings,
2283 .get_ethtool_stats = qeth_core_get_ethtool_stats,
Ben Hutchingsdf8b4ec2009-10-01 11:24:32 +00002284 .get_sset_count = qeth_core_get_sset_count,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002285 .get_drvinfo = qeth_core_get_drvinfo,
Julian Wiedmann993e19c2017-04-11 16:11:17 +02002286 .get_link_ksettings = qeth_core_ethtool_get_link_ksettings,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002287};
2288
2289/*
2290 * we need NOARP for IPv4 but we want neighbor solicitation for IPv6. Setting
2291 * NOARP on the netdevice is no option because it also turns off neighbor
2292 * solicitation. For IPv4 we install a neighbor_setup function. We don't want
2293 * arp resolution but we want the hard header (packet socket will work
2294 * e.g. tcpdump)
2295 */
2296static int qeth_l3_neigh_setup_noarp(struct neighbour *n)
2297{
2298 n->nud_state = NUD_NOARP;
2299 memcpy(n->ha, "FAKELL", 6);
2300 n->output = n->ops->connected_output;
2301 return 0;
2302}
2303
2304static int
2305qeth_l3_neigh_setup(struct net_device *dev, struct neigh_parms *np)
2306{
2307 if (np->tbl->family == AF_INET)
2308 np->neigh_setup = qeth_l3_neigh_setup_noarp;
2309
2310 return 0;
2311}
2312
Julian Wiedmannf13ade12018-09-17 17:35:56 +02002313static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb,
2314 struct net_device *dev,
2315 netdev_features_t features)
2316{
2317 if (qeth_get_ip_version(skb) != 4)
2318 features &= ~NETIF_F_HW_VLAN_CTAG_TX;
2319 return qeth_features_check(skb, dev, features);
2320}
2321
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002322static const struct net_device_ops qeth_l3_netdev_ops = {
Frank Blaschka8403b132009-01-08 10:50:55 -08002323 .ndo_open = qeth_l3_open,
2324 .ndo_stop = qeth_l3_stop,
2325 .ndo_get_stats = qeth_get_stats,
2326 .ndo_start_xmit = qeth_l3_hard_start_xmit,
2327 .ndo_validate_addr = eth_validate_addr,
Julian Wiedmann00c163f2017-12-20 20:11:02 +01002328 .ndo_set_rx_mode = qeth_l3_set_rx_mode,
Julian Wiedmann942d6982017-04-11 16:11:10 +02002329 .ndo_do_ioctl = qeth_do_ioctl,
Thomas Richter8f43fb02016-06-16 16:18:59 +02002330 .ndo_fix_features = qeth_fix_features,
2331 .ndo_set_features = qeth_set_features,
Frank Blaschka8403b132009-01-08 10:50:55 -08002332 .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
2333 .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00002334 .ndo_tx_timeout = qeth_tx_timeout,
Frank Blaschka8403b132009-01-08 10:50:55 -08002335};
2336
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002337static const struct net_device_ops qeth_l3_osa_netdev_ops = {
2338 .ndo_open = qeth_l3_open,
2339 .ndo_stop = qeth_l3_stop,
2340 .ndo_get_stats = qeth_get_stats,
2341 .ndo_start_xmit = qeth_l3_hard_start_xmit,
Julian Wiedmannf13ade12018-09-17 17:35:56 +02002342 .ndo_features_check = qeth_l3_osa_features_check,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002343 .ndo_validate_addr = eth_validate_addr,
Julian Wiedmann00c163f2017-12-20 20:11:02 +01002344 .ndo_set_rx_mode = qeth_l3_set_rx_mode,
Julian Wiedmann942d6982017-04-11 16:11:10 +02002345 .ndo_do_ioctl = qeth_do_ioctl,
Thomas Richter8f43fb02016-06-16 16:18:59 +02002346 .ndo_fix_features = qeth_fix_features,
2347 .ndo_set_features = qeth_set_features,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002348 .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
2349 .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00002350 .ndo_tx_timeout = qeth_tx_timeout,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002351 .ndo_neigh_setup = qeth_l3_neigh_setup,
2352};
2353
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002354static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002355{
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002356 unsigned int headroom;
Thomas Richter1aec42b2015-01-21 13:39:10 +01002357 int rc;
2358
Julian Wiedmann30356d02018-11-02 19:04:10 +01002359 if (qeth_netdev_is_registered(card->dev))
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002360 return 0;
2361
Ursula Braun5113fec2010-05-16 21:15:14 +00002362 if (card->info.type == QETH_CARD_TYPE_OSD ||
2363 card->info.type == QETH_CARD_TYPE_OSX) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01002364 if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
2365 (card->info.link_type == QETH_LINK_TYPE_HSTR)) {
Paul Gortmaker1abd2292012-05-10 15:50:52 -04002366 pr_info("qeth_l3: ignoring TR device\n");
2367 return -ENODEV;
Kittipon Meesompop1b811432018-04-26 09:42:16 +02002368 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002369
Kittipon Meesompop1b811432018-04-26 09:42:16 +02002370 card->dev->netdev_ops = &qeth_l3_osa_netdev_ops;
Julian Wiedmann0f342942018-03-09 18:12:54 +01002371
Kittipon Meesompop1b811432018-04-26 09:42:16 +02002372 /*IPv6 address autoconfiguration stuff*/
2373 qeth_l3_get_unique_id(card);
2374 if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
2375 card->dev->dev_id = card->info.unique_id & 0xffff;
Julian Wiedmann0f342942018-03-09 18:12:54 +01002376
Kittipon Meesompop1b811432018-04-26 09:42:16 +02002377 if (!card->info.guestlan) {
2378 card->dev->features |= NETIF_F_SG;
2379 card->dev->hw_features |= NETIF_F_TSO |
2380 NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
2381 card->dev->vlan_features |= NETIF_F_TSO |
2382 NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002383 }
Kittipon Meesompop571f9dd82018-04-26 09:42:22 +02002384
2385 if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) {
2386 card->dev->hw_features |= NETIF_F_IPV6_CSUM;
2387 card->dev->vlan_features |= NETIF_F_IPV6_CSUM;
2388 }
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002389 if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
2390 card->dev->hw_features |= NETIF_F_TSO6;
2391 card->dev->vlan_features |= NETIF_F_TSO6;
2392 }
2393
2394 /* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */
2395 if (card->dev->hw_features & NETIF_F_TSO6)
2396 headroom = sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
2397 else if (card->dev->hw_features & NETIF_F_TSO)
2398 headroom = sizeof(struct qeth_hdr_tso);
2399 else
2400 headroom = sizeof(struct qeth_hdr) + VLAN_HLEN;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002401 } else if (card->info.type == QETH_CARD_TYPE_IQD) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01002402 card->dev->flags |= IFF_NOARP;
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002403 card->dev->netdev_ops = &qeth_l3_netdev_ops;
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002404 headroom = sizeof(struct qeth_hdr) - ETH_HLEN;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002405
Thomas Richter1aec42b2015-01-21 13:39:10 +01002406 rc = qeth_l3_iqd_read_initial_mac(card);
2407 if (rc)
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002408 goto out;
2409
Frank Blaschkab3332932011-08-08 01:33:59 +00002410 if (card->options.hsuid[0])
2411 memcpy(card->dev->perm_addr, card->options.hsuid, 9);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002412 } else
2413 return -ENODEV;
2414
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002415 card->dev->needed_headroom = headroom;
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +00002416 card->dev->ethtool_ops = &qeth_l3_ethtool_ops;
Patrick McHardyf6469682013-04-19 02:04:27 +00002417 card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
2418 NETIF_F_HW_VLAN_CTAG_RX |
2419 NETIF_F_HW_VLAN_CTAG_FILTER;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002420
Eric Dumazet02875872014-10-05 18:38:35 -07002421 netif_keep_dst(card->dev);
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002422 if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6))
Julian Wiedmann371a1e72018-07-11 17:42:44 +02002423 netif_set_gso_max_size(card->dev,
2424 PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS(card) - 1));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002425
Julian Wiedmannd73ef322017-04-11 16:11:11 +02002426 netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002427 rc = register_netdev(card->dev);
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002428 if (!rc && carrier_ok)
2429 netif_carrier_on(card->dev);
2430
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002431out:
2432 if (rc)
2433 card->dev->netdev_ops = NULL;
2434 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002435}
2436
Ursula Braun79a04e42017-06-06 14:33:49 +02002437static const struct device_type qeth_l3_devtype = {
2438 .name = "qeth_layer3",
2439 .groups = qeth_l3_attr_groups,
2440};
2441
Frank Blaschka4a71df52008-02-15 09:19:42 +01002442static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
2443{
2444 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
Ursula Braun9111e782017-05-10 19:07:51 +02002445 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002446
Ursula Braun79a04e42017-06-06 14:33:49 +02002447 if (gdev->dev.type == &qeth_generic_devtype) {
2448 rc = qeth_l3_create_device_attributes(&gdev->dev);
2449 if (rc)
2450 return rc;
2451 }
Ursula Braunebccc7392017-05-10 19:07:54 +02002452 hash_init(card->ip_htable);
2453 hash_init(card->ip_mc_htable);
Frank Blaschka1da74b12011-05-12 18:45:02 +00002454 card->info.hwtrap = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002455 return 0;
2456}
2457
2458static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
2459{
2460 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
2461
Ursula Braun79a04e42017-06-06 14:33:49 +02002462 if (cgdev->dev.type == &qeth_generic_devtype)
2463 qeth_l3_remove_device_attributes(&cgdev->dev);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002464
Ursula Braunf2148562009-05-19 21:38:37 +00002465 qeth_set_allowed_threads(card, 0, 1);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002466 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
2467
Ursula Braun70919e22011-02-26 22:41:36 -08002468 if (cgdev->state == CCWGROUP_ONLINE)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002469 qeth_l3_set_offline(cgdev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002470
Julian Wiedmann30356d02018-11-02 19:04:10 +01002471 if (qeth_netdev_is_registered(card->dev))
2472 unregister_netdev(card->dev);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02002473 qeth_l3_clear_ip_htable(card, 0);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002474 qeth_l3_clear_ipato_list(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002475}
2476
2477static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
2478{
2479 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
2480 int rc = 0;
2481 enum qeth_card_states recover_flag;
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002482 bool carrier_ok;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002483
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002484 mutex_lock(&card->discipline_mutex);
Frank Blaschkac4949f02010-05-11 19:34:47 +00002485 mutex_lock(&card->conf_mutex);
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002486 QETH_DBF_TEXT(SETUP, 2, "setonlin");
2487 QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002488
Frank Blaschka4a71df52008-02-15 09:19:42 +01002489 recover_flag = card->state;
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002490 rc = qeth_core_hardsetup_card(card, &carrier_ok);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002491 if (rc) {
Thomas Richter1aec42b2015-01-21 13:39:10 +01002492 QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
Ursula Braunaa909222009-11-12 00:11:43 +00002493 rc = -ENODEV;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002494 goto out_remove;
2495 }
2496
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002497 rc = qeth_l3_setup_netdev(card, carrier_ok);
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002498 if (rc)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002499 goto out_remove;
2500
Frank Blaschka1da74b12011-05-12 18:45:02 +00002501 if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
2502 if (card->info.hwtrap &&
2503 qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))
2504 card->info.hwtrap = 0;
2505 } else
2506 card->info.hwtrap = 0;
2507
Frank Blaschka4a71df52008-02-15 09:19:42 +01002508 card->state = CARD_STATE_HARDSETUP;
2509 qeth_print_status_message(card);
2510
2511 /* softsetup */
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002512 QETH_DBF_TEXT(SETUP, 2, "softsetp");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002513
Frank Blaschka4a71df52008-02-15 09:19:42 +01002514 rc = qeth_l3_setadapter_parms(card);
2515 if (rc)
Thomas Richter1aec42b2015-01-21 13:39:10 +01002516 QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002517 if (!card->options.sniffer) {
2518 rc = qeth_l3_start_ipassists(card);
Stefan Raspl0f547612013-01-21 02:30:20 +00002519 if (rc) {
Ursula Braun76b11f82010-01-11 02:50:50 +00002520 QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
Stefan Raspl0f547612013-01-21 02:30:20 +00002521 goto out_remove;
2522 }
Ursula Braun76b11f82010-01-11 02:50:50 +00002523 rc = qeth_l3_setrouting_v4(card);
2524 if (rc)
Thomas Richter1aec42b2015-01-21 13:39:10 +01002525 QETH_DBF_TEXT_(SETUP, 2, "4err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002526 rc = qeth_l3_setrouting_v6(card);
2527 if (rc)
Thomas Richter1aec42b2015-01-21 13:39:10 +01002528 QETH_DBF_TEXT_(SETUP, 2, "5err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002529 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002530 netif_tx_disable(card->dev);
2531
2532 rc = qeth_init_qdio_queues(card);
2533 if (rc) {
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002534 QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
Ursula Braunaa909222009-11-12 00:11:43 +00002535 rc = -ENODEV;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002536 goto out_remove;
2537 }
2538 card->state = CARD_STATE_SOFTSETUP;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002539
2540 qeth_set_allowed_threads(card, 0xffffffff, 0);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02002541 qeth_l3_recover_ip(card);
Julian Wiedmannd025da92018-06-29 19:45:54 +02002542
2543 qeth_enable_hw_features(card->dev);
Frank Blaschka8af7c5a2008-04-24 10:15:25 +02002544 if (recover_flag == CARD_STATE_RECOVER) {
Ursula Braun4763b0a2011-12-19 22:56:32 +00002545 rtnl_lock();
Julian Wiedmann9aa17df2018-07-11 17:42:40 +02002546 if (recovery_mode) {
Ursula Braun39423442011-01-12 20:42:24 +00002547 __qeth_l3_open(card->dev);
Julian Wiedmann9aa17df2018-07-11 17:42:40 +02002548 qeth_l3_set_rx_mode(card->dev);
2549 } else {
Frank Blaschka8af7c5a2008-04-24 10:15:25 +02002550 dev_open(card->dev);
Julian Wiedmann9aa17df2018-07-11 17:42:40 +02002551 }
Ursula Braun4763b0a2011-12-19 22:56:32 +00002552 rtnl_unlock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002553 }
Stefan Raspl82f77cf2013-03-18 20:04:42 +00002554 qeth_trace_features(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002555 /* let user_space know that device is online */
2556 kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
Frank Blaschkac4949f02010-05-11 19:34:47 +00002557 mutex_unlock(&card->conf_mutex);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002558 mutex_unlock(&card->discipline_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002559 return 0;
2560out_remove:
Frank Blaschka4a71df52008-02-15 09:19:42 +01002561 qeth_l3_stop_card(card, 0);
2562 ccw_device_set_offline(CARD_DDEV(card));
2563 ccw_device_set_offline(CARD_WDEV(card));
2564 ccw_device_set_offline(CARD_RDEV(card));
Ursula Braun22ae2792014-02-24 13:12:06 +01002565 qdio_free(CARD_DDEV(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002566 if (recover_flag == CARD_STATE_RECOVER)
2567 card->state = CARD_STATE_RECOVER;
2568 else
2569 card->state = CARD_STATE_DOWN;
Frank Blaschkac4949f02010-05-11 19:34:47 +00002570 mutex_unlock(&card->conf_mutex);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002571 mutex_unlock(&card->discipline_mutex);
Ursula Braunaa909222009-11-12 00:11:43 +00002572 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002573}
2574
2575static int qeth_l3_set_online(struct ccwgroup_device *gdev)
2576{
2577 return __qeth_l3_set_online(gdev, 0);
2578}
2579
2580static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
2581 int recovery_mode)
2582{
2583 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
2584 int rc = 0, rc2 = 0, rc3 = 0;
2585 enum qeth_card_states recover_flag;
2586
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002587 mutex_lock(&card->discipline_mutex);
Frank Blaschkac4949f02010-05-11 19:34:47 +00002588 mutex_lock(&card->conf_mutex);
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002589 QETH_DBF_TEXT(SETUP, 3, "setoffl");
2590 QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002591
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002592 netif_carrier_off(card->dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002593 recover_flag = card->state;
Frank Blaschka1da74b12011-05-12 18:45:02 +00002594 if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
2595 qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
2596 card->info.hwtrap = 1;
2597 }
Ursula Braun0f5623c2008-10-24 11:16:52 +02002598 qeth_l3_stop_card(card, recovery_mode);
Einar Lueck72861ae2011-12-19 22:56:36 +00002599 if ((card->options.cq == QETH_CQ_ENABLED) && card->dev) {
2600 rtnl_lock();
2601 call_netdevice_notifiers(NETDEV_REBOOT, card->dev);
2602 rtnl_unlock();
2603 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002604 rc = ccw_device_set_offline(CARD_DDEV(card));
2605 rc2 = ccw_device_set_offline(CARD_WDEV(card));
2606 rc3 = ccw_device_set_offline(CARD_RDEV(card));
2607 if (!rc)
2608 rc = (rc2) ? rc2 : rc3;
2609 if (rc)
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002610 QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
Ursula Braun22ae2792014-02-24 13:12:06 +01002611 qdio_free(CARD_DDEV(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002612 if (recover_flag == CARD_STATE_UP)
2613 card->state = CARD_STATE_RECOVER;
2614 /* let user_space know that device is offline */
2615 kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
Frank Blaschkac4949f02010-05-11 19:34:47 +00002616 mutex_unlock(&card->conf_mutex);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002617 mutex_unlock(&card->discipline_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002618 return 0;
2619}
2620
2621static int qeth_l3_set_offline(struct ccwgroup_device *cgdev)
2622{
2623 return __qeth_l3_set_offline(cgdev, 0);
2624}
2625
2626static int qeth_l3_recover(void *ptr)
2627{
2628 struct qeth_card *card;
2629 int rc = 0;
2630
2631 card = (struct qeth_card *) ptr;
Carsten Otte847a50f2010-06-21 22:57:05 +00002632 QETH_CARD_TEXT(card, 2, "recover1");
2633 QETH_CARD_HEX(card, 2, &card, sizeof(void *));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002634 if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
2635 return 0;
Carsten Otte847a50f2010-06-21 22:57:05 +00002636 QETH_CARD_TEXT(card, 2, "recover2");
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002637 dev_warn(&card->gdev->dev,
2638 "A recovery process has been started for the device\n");
Stefan Raspl65d80132013-04-07 22:19:27 +00002639 qeth_set_recovery_task(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002640 __qeth_l3_set_offline(card->gdev, 1);
2641 rc = __qeth_l3_set_online(card->gdev, 1);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002642 if (!rc)
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002643 dev_info(&card->gdev->dev,
2644 "Device successfully recovered!\n");
Ursula Braun28a7e4c2008-09-19 12:56:03 +02002645 else {
Stefan Raspl0f547612013-01-21 02:30:20 +00002646 qeth_close_dev(card);
2647 dev_warn(&card->gdev->dev, "The qeth device driver "
Stefan Raspl2efaf5f2012-10-15 19:21:18 +00002648 "failed to recover an error on the device\n");
Ursula Braun28a7e4c2008-09-19 12:56:03 +02002649 }
Stefan Raspl65d80132013-04-07 22:19:27 +00002650 qeth_clear_recovery_task(card);
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002651 qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
2652 qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002653 return 0;
2654}
2655
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002656static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
2657{
2658 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
2659
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002660 netif_device_detach(card->dev);
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002661 qeth_set_allowed_threads(card, 0, 1);
2662 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
2663 if (gdev->state == CCWGROUP_OFFLINE)
2664 return 0;
2665 if (card->state == CARD_STATE_UP) {
Frank Blaschka1da74b12011-05-12 18:45:02 +00002666 if (card->info.hwtrap)
2667 qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002668 __qeth_l3_set_offline(card->gdev, 1);
2669 } else
2670 __qeth_l3_set_offline(card->gdev, 0);
2671 return 0;
2672}
2673
2674static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
2675{
2676 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
2677 int rc = 0;
2678
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002679 if (card->state == CARD_STATE_RECOVER) {
2680 rc = __qeth_l3_set_online(card->gdev, 1);
2681 if (rc) {
Ursula Braun869da902010-03-08 20:36:56 +00002682 rtnl_lock();
2683 dev_close(card->dev);
2684 rtnl_unlock();
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002685 }
2686 } else
2687 rc = __qeth_l3_set_online(card->gdev, 0);
Julian Wiedmann6585ac42018-09-26 18:29:12 +02002688
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002689 qeth_set_allowed_threads(card, 0xffffffff, 0);
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002690 netif_device_attach(card->dev);
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002691 if (rc)
2692 dev_warn(&card->gdev->dev, "The qeth device driver "
2693 "failed to recover an error on the device\n");
2694 return rc;
2695}
2696
Eugene Crosserc044dc22014-01-29 09:23:48 +01002697/* Returns zero if the command is successfully "consumed" */
2698static int qeth_l3_control_event(struct qeth_card *card,
2699 struct qeth_ipa_cmd *cmd)
2700{
2701 return 1;
2702}
2703
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002704struct qeth_discipline qeth_l3_discipline = {
Ursula Braun79a04e42017-06-06 14:33:49 +02002705 .devtype = &qeth_l3_devtype,
Julian Wiedmannd73ef322017-04-11 16:11:11 +02002706 .process_rx_buffer = qeth_l3_process_inbound_buffer,
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002707 .recover = qeth_l3_recover,
2708 .setup = qeth_l3_probe_device,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002709 .remove = qeth_l3_remove_device,
2710 .set_online = qeth_l3_set_online,
2711 .set_offline = qeth_l3_set_offline,
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002712 .freeze = qeth_l3_pm_suspend,
2713 .thaw = qeth_l3_pm_resume,
2714 .restore = qeth_l3_pm_resume,
Julian Wiedmann942d6982017-04-11 16:11:10 +02002715 .do_ioctl = qeth_l3_do_ioctl,
Eugene Crosserc044dc22014-01-29 09:23:48 +01002716 .control_event_handler = qeth_l3_control_event,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002717};
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002718EXPORT_SYMBOL_GPL(qeth_l3_discipline);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002719
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002720static int qeth_l3_handle_ip_event(struct qeth_card *card,
2721 struct qeth_ipaddr *addr,
2722 unsigned long event)
2723{
2724 switch (event) {
2725 case NETDEV_UP:
2726 spin_lock_bh(&card->ip_lock);
2727 qeth_l3_add_ip(card, addr);
2728 spin_unlock_bh(&card->ip_lock);
2729 return NOTIFY_OK;
2730 case NETDEV_DOWN:
2731 spin_lock_bh(&card->ip_lock);
2732 qeth_l3_delete_ip(card, addr);
2733 spin_unlock_bh(&card->ip_lock);
2734 return NOTIFY_OK;
2735 default:
2736 return NOTIFY_DONE;
2737 }
2738}
2739
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002740static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev)
2741{
2742 if (is_vlan_dev(dev))
2743 dev = vlan_dev_real_dev(dev);
2744 if (dev->netdev_ops == &qeth_l3_osa_netdev_ops ||
2745 dev->netdev_ops == &qeth_l3_netdev_ops)
2746 return (struct qeth_card *) dev->ml_priv;
2747 return NULL;
2748}
2749
Frank Blaschka4a71df52008-02-15 09:19:42 +01002750static int qeth_l3_ip_event(struct notifier_block *this,
David S. Miller76fef2b2008-03-22 18:22:42 -07002751 unsigned long event, void *ptr)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002752{
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02002753
Frank Blaschka4a71df52008-02-15 09:19:42 +01002754 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002755 struct net_device *dev = ifa->ifa_dev->dev;
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002756 struct qeth_ipaddr addr;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002757 struct qeth_card *card;
2758
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002759 if (dev_net(dev) != &init_net)
David S. Miller76fef2b2008-03-22 18:22:42 -07002760 return NOTIFY_DONE;
2761
Frank Blaschka4a71df52008-02-15 09:19:42 +01002762 card = qeth_l3_get_card_from_dev(dev);
2763 if (!card)
2764 return NOTIFY_DONE;
frank.blaschka@de.ibm.com6d8823d2012-05-16 01:28:26 +00002765 QETH_CARD_TEXT(card, 3, "ipevent");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002766
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002767 qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV4);
2768 addr.u.a4.addr = be32_to_cpu(ifa->ifa_address);
2769 addr.u.a4.mask = be32_to_cpu(ifa->ifa_mask);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002770
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002771 return qeth_l3_handle_ip_event(card, &addr, event);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002772}
2773
2774static struct notifier_block qeth_l3_ip_notifier = {
2775 qeth_l3_ip_event,
2776 NULL,
2777};
2778
Frank Blaschka4a71df52008-02-15 09:19:42 +01002779static int qeth_l3_ip6_event(struct notifier_block *this,
David S. Miller76fef2b2008-03-22 18:22:42 -07002780 unsigned long event, void *ptr)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002781{
2782 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002783 struct net_device *dev = ifa->idev->dev;
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002784 struct qeth_ipaddr addr;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002785 struct qeth_card *card;
2786
Frank Blaschka4a71df52008-02-15 09:19:42 +01002787 card = qeth_l3_get_card_from_dev(dev);
2788 if (!card)
2789 return NOTIFY_DONE;
Carsten Otte847a50f2010-06-21 22:57:05 +00002790 QETH_CARD_TEXT(card, 3, "ip6event");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002791 if (!qeth_is_supported(card, IPA_IPV6))
2792 return NOTIFY_DONE;
2793
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002794 qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6);
2795 addr.u.a6.addr = ifa->addr;
2796 addr.u.a6.pfxlen = ifa->prefix_len;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002797
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002798 return qeth_l3_handle_ip_event(card, &addr, event);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002799}
2800
2801static struct notifier_block qeth_l3_ip6_notifier = {
2802 qeth_l3_ip6_event,
2803 NULL,
2804};
Frank Blaschka4a71df52008-02-15 09:19:42 +01002805
2806static int qeth_l3_register_notifiers(void)
2807{
2808 int rc;
2809
Carsten Otte847a50f2010-06-21 22:57:05 +00002810 QETH_DBF_TEXT(SETUP, 5, "regnotif");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002811 rc = register_inetaddr_notifier(&qeth_l3_ip_notifier);
2812 if (rc)
2813 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002814 rc = register_inet6addr_notifier(&qeth_l3_ip6_notifier);
2815 if (rc) {
2816 unregister_inetaddr_notifier(&qeth_l3_ip_notifier);
2817 return rc;
2818 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002819 return 0;
2820}
2821
2822static void qeth_l3_unregister_notifiers(void)
2823{
Carsten Otte847a50f2010-06-21 22:57:05 +00002824 QETH_DBF_TEXT(SETUP, 5, "unregnot");
Stefan Raspl18af5c12012-11-19 02:46:50 +00002825 WARN_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier));
Stefan Raspl18af5c12012-11-19 02:46:50 +00002826 WARN_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002827}
2828
2829static int __init qeth_l3_init(void)
2830{
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002831 pr_info("register layer 3 discipline\n");
Julian Wiedmannc0622042017-12-20 20:10:58 +01002832 return qeth_l3_register_notifiers();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002833}
2834
2835static void __exit qeth_l3_exit(void)
2836{
2837 qeth_l3_unregister_notifiers();
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002838 pr_info("unregister layer 3 discipline\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002839}
2840
2841module_init(qeth_l3_init);
2842module_exit(qeth_l3_exit);
2843MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
2844MODULE_DESCRIPTION("qeth layer 3 discipline");
2845MODULE_LICENSE("GPL");