blob: f08b745c20073b92bd2a78da983ff2a9ade3ca77 [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
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001780static int qeth_l3_arp_modify_entry(struct qeth_card *card,
1781 struct qeth_arp_cache_entry *entry,
1782 enum qeth_arp_process_subcmds arp_cmd)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001783{
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001784 struct qeth_arp_cache_entry *cmd_entry;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001785 struct qeth_cmd_buffer *iob;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001786 int rc;
1787
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001788 if (arp_cmd == IPA_CMD_ASS_ARP_ADD_ENTRY)
1789 QETH_CARD_TEXT(card, 3, "arpadd");
1790 else
1791 QETH_CARD_TEXT(card, 3, "arpdel");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001792
1793 /*
1794 * currently GuestLAN only supports the ARP assist function
1795 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_ADD_ENTRY;
1796 * thus we say EOPNOTSUPP for this ARP function
1797 */
1798 if (card->info.guestlan)
1799 return -EOPNOTSUPP;
1800 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001801 return -EOPNOTSUPP;
1802 }
1803
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001804 iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING, arp_cmd,
1805 sizeof(*cmd_entry), QETH_PROT_IPV4);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001806 if (!iob)
1807 return -ENOMEM;
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001808
1809 cmd_entry = &__ipa_cmd(iob)->data.setassparms.data.arp_entry;
1810 ether_addr_copy(cmd_entry->macaddr, entry->macaddr);
1811 memcpy(cmd_entry->ipaddr, entry->ipaddr, 4);
1812 rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_cb, NULL);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001813 if (rc)
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001814 QETH_DBF_MESSAGE(2, "Could not modify (cmd: %#x) ARP entry on device %x: %#x\n",
1815 arp_cmd, CARD_DEVID(card), rc);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001816
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001817 return qeth_l3_arp_makerc(rc);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001818}
1819
1820static int qeth_l3_arp_flush_cache(struct qeth_card *card)
1821{
1822 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001823
Carsten Otte847a50f2010-06-21 22:57:05 +00001824 QETH_CARD_TEXT(card, 3, "arpflush");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001825
1826 /*
1827 * currently GuestLAN only supports the ARP assist function
1828 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_FLUSH_CACHE;
1829 * thus we say EOPNOTSUPP for this ARP function
1830 */
1831 if (card->info.guestlan || (card->info.type == QETH_CARD_TYPE_IQD))
1832 return -EOPNOTSUPP;
1833 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001834 return -EOPNOTSUPP;
1835 }
Thomas Richter4d7def22015-09-18 16:06:51 +02001836 rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
Frank Blaschka4a71df52008-02-15 09:19:42 +01001837 IPA_CMD_ASS_ARP_FLUSH_CACHE, 0);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001838 if (rc)
1839 QETH_DBF_MESSAGE(2, "Could not flush ARP cache on device %x: %#x\n",
1840 CARD_DEVID(card), rc);
1841 return qeth_l3_arp_makerc(rc);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001842}
1843
1844static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
1845{
Heiko Carstens509e2562008-07-26 02:24:10 -07001846 struct qeth_card *card = dev->ml_priv;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001847 struct qeth_arp_cache_entry arp_entry;
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001848 enum qeth_arp_process_subcmds arp_cmd;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001849 int rc = 0;
1850
Frank Blaschka4a71df52008-02-15 09:19:42 +01001851 switch (cmd) {
1852 case SIOC_QETH_ARP_SET_NO_ENTRIES:
1853 if (!capable(CAP_NET_ADMIN)) {
1854 rc = -EPERM;
1855 break;
1856 }
1857 rc = qeth_l3_arp_set_no_entries(card, rq->ifr_ifru.ifru_ivalue);
1858 break;
1859 case SIOC_QETH_ARP_QUERY_INFO:
1860 if (!capable(CAP_NET_ADMIN)) {
1861 rc = -EPERM;
1862 break;
1863 }
1864 rc = qeth_l3_arp_query(card, rq->ifr_ifru.ifru_data);
1865 break;
1866 case SIOC_QETH_ARP_ADD_ENTRY:
Frank Blaschka4a71df52008-02-15 09:19:42 +01001867 case SIOC_QETH_ARP_REMOVE_ENTRY:
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001868 if (!capable(CAP_NET_ADMIN))
1869 return -EPERM;
1870 if (copy_from_user(&arp_entry, rq->ifr_data, sizeof(arp_entry)))
1871 return -EFAULT;
1872
1873 arp_cmd = (cmd == SIOC_QETH_ARP_ADD_ENTRY) ?
1874 IPA_CMD_ASS_ARP_ADD_ENTRY :
1875 IPA_CMD_ASS_ARP_REMOVE_ENTRY;
1876 return qeth_l3_arp_modify_entry(card, &arp_entry, arp_cmd);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001877 case SIOC_QETH_ARP_FLUSH_CACHE:
1878 if (!capable(CAP_NET_ADMIN)) {
1879 rc = -EPERM;
1880 break;
1881 }
1882 rc = qeth_l3_arp_flush_cache(card);
1883 break;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001884 default:
1885 rc = -EOPNOTSUPP;
1886 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001887 return rc;
1888}
1889
Julian Wiedmann1f979122017-12-20 20:11:04 +01001890static int qeth_l3_get_cast_type(struct sk_buff *skb)
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001891{
David S. Miller69cce1d2011-07-17 23:09:49 -07001892 struct neighbour *n = NULL;
1893 struct dst_entry *dst;
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001894
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001895 rcu_read_lock();
David S. Miller69cce1d2011-07-17 23:09:49 -07001896 dst = skb_dst(skb);
1897 if (dst)
David S. Miller24db1ba2012-07-02 22:02:33 -07001898 n = dst_neigh_lookup_skb(dst, skb);
David S. Miller69cce1d2011-07-17 23:09:49 -07001899 if (n) {
Julian Wiedmann1f979122017-12-20 20:11:04 +01001900 int cast_type = n->type;
1901
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001902 rcu_read_unlock();
David S. Miller24db1ba2012-07-02 22:02:33 -07001903 neigh_release(n);
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001904 if ((cast_type == RTN_BROADCAST) ||
1905 (cast_type == RTN_MULTICAST) ||
1906 (cast_type == RTN_ANYCAST))
1907 return cast_type;
Julian Wiedmann86c0cdb2018-07-11 17:42:41 +02001908 return RTN_UNICAST;
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001909 }
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001910 rcu_read_unlock();
1911
Julian Wiedmann1f979122017-12-20 20:11:04 +01001912 /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001913 switch (qeth_get_ip_version(skb)) {
1914 case 4:
Julian Wiedmann1f979122017-12-20 20:11:04 +01001915 return ipv4_is_multicast(ip_hdr(skb)->daddr) ?
Julian Wiedmann86c0cdb2018-07-11 17:42:41 +02001916 RTN_MULTICAST : RTN_UNICAST;
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001917 case 6:
1918 return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
1919 RTN_MULTICAST : RTN_UNICAST;
1920 default:
1921 /* ... and MAC address */
1922 if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest,
1923 skb->dev->broadcast))
1924 return RTN_BROADCAST;
1925 if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
1926 return RTN_MULTICAST;
1927 /* default to unicast */
1928 return RTN_UNICAST;
1929 }
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001930}
1931
Julian Wiedmanna647a022018-07-11 17:42:46 +02001932static void qeth_l3_fill_af_iucv_hdr(struct qeth_hdr *hdr, struct sk_buff *skb,
1933 unsigned int data_len)
Frank Blaschkab3332932011-08-08 01:33:59 +00001934{
1935 char daddr[16];
Frank Blaschkab3332932011-08-08 01:33:59 +00001936
Frank Blaschkab3332932011-08-08 01:33:59 +00001937 hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
Julian Wiedmanna647a022018-07-11 17:42:46 +02001938 hdr->hdr.l3.length = data_len;
Frank Blaschkab3332932011-08-08 01:33:59 +00001939 hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
Julian Wiedmannacd97762017-03-23 14:55:09 +01001940
Frank Blaschkab3332932011-08-08 01:33:59 +00001941 memset(daddr, 0, sizeof(daddr));
1942 daddr[0] = 0xfe;
1943 daddr[1] = 0x80;
Julian Wiedmanncd11d112018-09-26 18:29:06 +02001944 memcpy(&daddr[8], iucv_trans_hdr(skb)->destUserID, 8);
Julian Wiedmanna8433832017-12-20 20:11:06 +01001945 memcpy(hdr->hdr.l3.next_hop.ipv6_addr, daddr, 16);
Frank Blaschkab3332932011-08-08 01:33:59 +00001946}
1947
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001948static u8 qeth_l3_cast_type_to_flag(int cast_type)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001949{
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001950 if (cast_type == RTN_MULTICAST)
1951 return QETH_CAST_MULTICAST;
1952 if (cast_type == RTN_ANYCAST)
1953 return QETH_CAST_ANYCAST;
1954 if (cast_type == RTN_BROADCAST)
1955 return QETH_CAST_BROADCAST;
1956 return QETH_CAST_UNICAST;
1957}
David S. Miller69cce1d2011-07-17 23:09:49 -07001958
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001959static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
Julian Wiedmannf6c13142017-12-20 20:11:08 +01001960 struct sk_buff *skb, int ipv, int cast_type,
1961 unsigned int data_len)
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001962{
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001963 struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
1964
Julian Wiedmannf6c13142017-12-20 20:11:08 +01001965 hdr->hdr.l3.length = data_len;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001966
Julian Wiedmanne517b642018-09-17 17:36:02 +02001967 if (skb_is_gso(skb)) {
Julian Wiedmann0aef8392018-10-12 17:27:15 +02001968 hdr->hdr.l3.id = QETH_HEADER_TYPE_L3_TSO;
Julian Wiedmanne517b642018-09-17 17:36:02 +02001969 } else {
1970 hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
1971 if (skb->ip_summed == CHECKSUM_PARTIAL) {
1972 qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv);
1973 /* some HW requires combined L3+L4 csum offload: */
1974 if (ipv == 4)
1975 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ;
1976 if (card->options.performance_stats)
1977 card->perf_stats.tx_csum++;
1978 }
1979 }
1980
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001981 if (ipv == 4 || IS_IQD(card)) {
1982 /* NETIF_F_HW_VLAN_CTAG_TX */
1983 if (skb_vlan_tag_present(skb)) {
1984 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_VLAN_FRAME;
1985 hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
1986 }
1987 } else if (veth->h_vlan_proto == htons(ETH_P_8021Q)) {
1988 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_INCLUDE_VLAN_TAG;
1989 hdr->hdr.l3.vlan_id = ntohs(veth->h_vlan_TCI);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001990 }
1991
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001992 /* OSA only: */
1993 if (!ipv) {
1994 hdr->hdr.l3.flags = QETH_HDR_PASSTHRU;
1995 if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest,
1996 skb->dev->broadcast))
1997 hdr->hdr.l3.flags |= QETH_CAST_BROADCAST;
1998 else
1999 hdr->hdr.l3.flags |= (cast_type == RTN_MULTICAST) ?
2000 QETH_CAST_MULTICAST : QETH_CAST_UNICAST;
2001 return;
2002 }
Frank Blaschka1d36cb42011-11-15 02:31:15 +00002003
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002004 hdr->hdr.l3.flags = qeth_l3_cast_type_to_flag(cast_type);
Frank Blaschka1d36cb42011-11-15 02:31:15 +00002005 rcu_read_lock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002006 if (ipv == 4) {
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002007 struct rtable *rt = skb_rtable(skb);
David Miller87e75972012-02-01 10:49:17 +00002008
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002009 *((__be32 *) &hdr->hdr.l3.next_hop.ipv4.addr) = (rt) ?
2010 rt_nexthop(rt, ip_hdr(skb)->daddr) :
2011 ip_hdr(skb)->daddr;
2012 } else {
2013 /* IPv6 */
2014 const struct rt6_info *rt = skb_rt6_info(skb);
2015 const struct in6_addr *next_hop;
David Miller87e75972012-02-01 10:49:17 +00002016
Julian Wiedmannec2c6722017-08-07 13:28:39 +02002017 if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002018 next_hop = &rt->rt6i_gateway;
2019 else
2020 next_hop = &ipv6_hdr(skb)->daddr;
2021 memcpy(hdr->hdr.l3.next_hop.ipv6_addr, next_hop, 16);
David Miller87e75972012-02-01 10:49:17 +00002022
Julian Wiedmann910a0a82017-12-20 20:11:07 +01002023 hdr->hdr.l3.flags |= QETH_HDR_IPV6;
2024 if (card->info.type != QETH_CARD_TYPE_IQD)
2025 hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002026 }
Frank Blaschka1d36cb42011-11-15 02:31:15 +00002027 rcu_read_unlock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002028}
2029
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02002030static void qeth_l3_fixup_headers(struct sk_buff *skb)
2031{
2032 struct iphdr *iph = ip_hdr(skb);
2033
2034 /* this is safe, IPv6 traffic takes a different path */
2035 if (skb->ip_summed == CHECKSUM_PARTIAL)
2036 iph->check = 0;
Julian Wiedmanne517b642018-09-17 17:36:02 +02002037 if (skb_is_gso(skb)) {
2038 iph->tot_len = 0;
2039 tcp_hdr(skb)->check = ~tcp_v4_check(0, iph->saddr,
2040 iph->daddr, 0);
2041 }
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02002042}
2043
Julian Wiedmann356156b2018-09-17 17:36:03 +02002044static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
2045 struct qeth_qdio_out_q *queue, int ipv, int cast_type)
Julian Wiedmanna647a022018-07-11 17:42:46 +02002046{
Julian Wiedmanne517b642018-09-17 17:36:02 +02002047 unsigned int hw_hdr_len, proto_len, frame_len, elements;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002048 unsigned char eth_hdr[ETH_HLEN];
Julian Wiedmanne517b642018-09-17 17:36:02 +02002049 bool is_tso = skb_is_gso(skb);
2050 unsigned int data_offset = 0;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002051 struct qeth_hdr *hdr = NULL;
2052 unsigned int hd_len = 0;
Julian Wiedmannba86ceee2018-07-19 12:43:56 +02002053 int push_len, rc;
Julian Wiedmannd2a274b2018-07-19 12:43:55 +02002054 bool is_sg;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002055
Julian Wiedmanne517b642018-09-17 17:36:02 +02002056 if (is_tso) {
2057 hw_hdr_len = sizeof(struct qeth_hdr_tso);
2058 proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb) -
2059 ETH_HLEN;
2060 } else {
2061 hw_hdr_len = sizeof(struct qeth_hdr);
2062 proto_len = 0;
2063 }
2064
Julian Wiedmanna647a022018-07-11 17:42:46 +02002065 /* re-use the L2 header area for the HW header: */
2066 rc = skb_cow_head(skb, hw_hdr_len - ETH_HLEN);
2067 if (rc)
2068 return rc;
2069 skb_copy_from_linear_data(skb, eth_hdr, ETH_HLEN);
2070 skb_pull(skb, ETH_HLEN);
2071 frame_len = skb->len;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002072
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02002073 qeth_l3_fixup_headers(skb);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002074 push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len,
Julian Wiedmanna7c2f4a2018-07-19 12:43:57 +02002075 &elements);
Julian Wiedmanna647a022018-07-11 17:42:46 +02002076 if (push_len < 0)
2077 return push_len;
Julian Wiedmanne517b642018-09-17 17:36:02 +02002078 if (is_tso || !push_len) {
2079 /* HW header needs its own buffer element. */
2080 hd_len = hw_hdr_len + proto_len;
2081 data_offset = push_len + proto_len;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002082 }
Julian Wiedmanne517b642018-09-17 17:36:02 +02002083 memset(hdr, 0, hw_hdr_len);
Julian Wiedmanna647a022018-07-11 17:42:46 +02002084
Julian Wiedmanne517b642018-09-17 17:36:02 +02002085 if (skb->protocol == htons(ETH_P_AF_IUCV)) {
Julian Wiedmanna647a022018-07-11 17:42:46 +02002086 qeth_l3_fill_af_iucv_hdr(hdr, skb, frame_len);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002087 } else {
Julian Wiedmanna647a022018-07-11 17:42:46 +02002088 qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002089 if (is_tso)
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002090 qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr,
2091 frame_len - proto_len, skb,
2092 proto_len);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002093 }
Julian Wiedmanna647a022018-07-11 17:42:46 +02002094
Julian Wiedmannd2a274b2018-07-19 12:43:55 +02002095 is_sg = skb_is_nonlinear(skb);
Julian Wiedmannfb321f22018-07-11 17:42:47 +02002096 if (IS_IQD(card)) {
Julian Wiedmanne517b642018-09-17 17:36:02 +02002097 rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset,
2098 hd_len);
Julian Wiedmannfb321f22018-07-11 17:42:47 +02002099 } else {
2100 /* TODO: drop skb_orphan() once TX completion is fast enough */
2101 skb_orphan(skb);
Julian Wiedmanne517b642018-09-17 17:36:02 +02002102 rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset,
2103 hd_len, elements);
Julian Wiedmannfb321f22018-07-11 17:42:47 +02002104 }
Julian Wiedmannba86ceee2018-07-19 12:43:56 +02002105
Julian Wiedmanna647a022018-07-11 17:42:46 +02002106 if (!rc) {
Julian Wiedmannd2a274b2018-07-19 12:43:55 +02002107 if (card->options.performance_stats) {
2108 card->perf_stats.buf_elements_sent += elements;
2109 if (is_sg)
2110 card->perf_stats.sg_skbs_sent++;
Julian Wiedmanne517b642018-09-17 17:36:02 +02002111 if (is_tso) {
2112 card->perf_stats.large_send_bytes += frame_len;
2113 card->perf_stats.large_send_cnt++;
2114 }
Julian Wiedmanna647a022018-07-11 17:42:46 +02002115 }
2116 } else {
2117 if (!push_len)
2118 kmem_cache_free(qeth_core_header_cache, hdr);
2119 if (rc == -EBUSY) {
2120 /* roll back to ETH header */
2121 skb_pull(skb, push_len);
2122 skb_push(skb, ETH_HLEN);
2123 skb_copy_to_linear_data(skb, eth_hdr, ETH_HLEN);
2124 }
2125 }
2126 return rc;
2127}
2128
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02002129static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
2130 struct net_device *dev)
2131{
2132 int cast_type = qeth_l3_get_cast_type(skb);
2133 struct qeth_card *card = dev->ml_priv;
2134 int ipv = qeth_get_ip_version(skb);
2135 struct qeth_qdio_out_q *queue;
2136 int tx_bytes = skb->len;
2137 int rc;
2138
2139 if (IS_IQD(card)) {
2140 if (card->options.sniffer)
2141 goto tx_drop;
2142 if ((card->options.cq != QETH_CQ_ENABLED && !ipv) ||
2143 (card->options.cq == QETH_CQ_ENABLED &&
2144 skb->protocol != htons(ETH_P_AF_IUCV)))
Frank Blaschka4a71df52008-02-15 09:19:42 +01002145 goto tx_drop;
2146 }
2147
Julian Wiedmann91cc98f2018-09-26 18:29:16 +02002148 if (card->state != CARD_STATE_UP) {
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02002149 card->stats.tx_carrier_errors++;
2150 goto tx_drop;
2151 }
2152
2153 if (cast_type == RTN_BROADCAST && !card->info.broadcast_capable)
2154 goto tx_drop;
2155
2156 queue = qeth_get_tx_queue(card, skb, ipv, cast_type);
2157
2158 if (card->options.performance_stats) {
2159 card->perf_stats.outbound_cnt++;
2160 card->perf_stats.outbound_start_time = qeth_get_micros();
2161 }
2162 netif_stop_queue(dev);
2163
Julian Wiedmann356156b2018-09-17 17:36:03 +02002164 if (ipv == 4 || IS_IQD(card))
Julian Wiedmanna647a022018-07-11 17:42:46 +02002165 rc = qeth_l3_xmit(card, skb, queue, ipv, cast_type);
Julian Wiedmannf13ade12018-09-17 17:35:56 +02002166 else
2167 rc = qeth_xmit(card, skb, queue, ipv, cast_type,
2168 qeth_l3_fill_header);
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02002169
2170 if (!rc) {
2171 card->stats.tx_packets++;
2172 card->stats.tx_bytes += tx_bytes;
2173 if (card->options.performance_stats)
2174 card->perf_stats.outbound_time += qeth_get_micros() -
2175 card->perf_stats.outbound_start_time;
2176 netif_wake_queue(dev);
2177 return NETDEV_TX_OK;
2178 } else if (rc == -EBUSY) {
2179 return NETDEV_TX_BUSY;
2180 } /* else fall through */
Frank Blaschka4a71df52008-02-15 09:19:42 +01002181
2182tx_drop:
2183 card->stats.tx_dropped++;
2184 card->stats.tx_errors++;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002185 dev_kfree_skb_any(skb);
Frank Blaschkad0ec0f52008-06-06 12:37:48 +02002186 netif_wake_queue(dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002187 return NETDEV_TX_OK;
2188}
2189
Ursula Braun39423442011-01-12 20:42:24 +00002190static int __qeth_l3_open(struct net_device *dev)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002191{
Heiko Carstens509e2562008-07-26 02:24:10 -07002192 struct qeth_card *card = dev->ml_priv;
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002193 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002194
Carsten Otte847a50f2010-06-21 22:57:05 +00002195 QETH_CARD_TEXT(card, 4, "qethopen");
Ursula Braun39423442011-01-12 20:42:24 +00002196 if (card->state == CARD_STATE_UP)
2197 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002198 if (card->state != CARD_STATE_SOFTSETUP)
2199 return -ENODEV;
2200 card->data.state = CH_STATE_UP;
2201 card->state = CARD_STATE_UP;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002202 netif_start_queue(dev);
2203
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002204 if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
2205 napi_enable(&card->napi);
Julian Wiedmann4d19db72018-09-17 17:36:06 +02002206 local_bh_disable();
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002207 napi_schedule(&card->napi);
Julian Wiedmann4d19db72018-09-17 17:36:06 +02002208 /* kick-start the NAPI softirq: */
2209 local_bh_enable();
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002210 } else
2211 rc = -EIO;
2212 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002213}
2214
Ursula Braun39423442011-01-12 20:42:24 +00002215static int qeth_l3_open(struct net_device *dev)
2216{
2217 struct qeth_card *card = dev->ml_priv;
2218
2219 QETH_CARD_TEXT(card, 5, "qethope_");
2220 if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
2221 QETH_CARD_TEXT(card, 3, "openREC");
2222 return -ERESTARTSYS;
2223 }
2224 return __qeth_l3_open(dev);
2225}
2226
Frank Blaschka4a71df52008-02-15 09:19:42 +01002227static int qeth_l3_stop(struct net_device *dev)
2228{
Heiko Carstens509e2562008-07-26 02:24:10 -07002229 struct qeth_card *card = dev->ml_priv;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002230
Carsten Otte847a50f2010-06-21 22:57:05 +00002231 QETH_CARD_TEXT(card, 4, "qethstop");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002232 netif_tx_disable(dev);
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002233 if (card->state == CARD_STATE_UP) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01002234 card->state = CARD_STATE_SOFTSETUP;
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002235 napi_disable(&card->napi);
2236 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002237 return 0;
2238}
2239
Stephen Hemminger0fc0b732009-09-02 01:03:33 -07002240static const struct ethtool_ops qeth_l3_ethtool_ops = {
Frank Blaschka4a71df52008-02-15 09:19:42 +01002241 .get_link = ethtool_op_get_link,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002242 .get_strings = qeth_core_get_strings,
2243 .get_ethtool_stats = qeth_core_get_ethtool_stats,
Ben Hutchingsdf8b4ec2009-10-01 11:24:32 +00002244 .get_sset_count = qeth_core_get_sset_count,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002245 .get_drvinfo = qeth_core_get_drvinfo,
Julian Wiedmann993e19c2017-04-11 16:11:17 +02002246 .get_link_ksettings = qeth_core_ethtool_get_link_ksettings,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002247};
2248
2249/*
2250 * we need NOARP for IPv4 but we want neighbor solicitation for IPv6. Setting
2251 * NOARP on the netdevice is no option because it also turns off neighbor
2252 * solicitation. For IPv4 we install a neighbor_setup function. We don't want
2253 * arp resolution but we want the hard header (packet socket will work
2254 * e.g. tcpdump)
2255 */
2256static int qeth_l3_neigh_setup_noarp(struct neighbour *n)
2257{
2258 n->nud_state = NUD_NOARP;
2259 memcpy(n->ha, "FAKELL", 6);
2260 n->output = n->ops->connected_output;
2261 return 0;
2262}
2263
2264static int
2265qeth_l3_neigh_setup(struct net_device *dev, struct neigh_parms *np)
2266{
2267 if (np->tbl->family == AF_INET)
2268 np->neigh_setup = qeth_l3_neigh_setup_noarp;
2269
2270 return 0;
2271}
2272
Julian Wiedmannf13ade12018-09-17 17:35:56 +02002273static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb,
2274 struct net_device *dev,
2275 netdev_features_t features)
2276{
2277 if (qeth_get_ip_version(skb) != 4)
2278 features &= ~NETIF_F_HW_VLAN_CTAG_TX;
2279 return qeth_features_check(skb, dev, features);
2280}
2281
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002282static const struct net_device_ops qeth_l3_netdev_ops = {
Frank Blaschka8403b132009-01-08 10:50:55 -08002283 .ndo_open = qeth_l3_open,
2284 .ndo_stop = qeth_l3_stop,
2285 .ndo_get_stats = qeth_get_stats,
2286 .ndo_start_xmit = qeth_l3_hard_start_xmit,
2287 .ndo_validate_addr = eth_validate_addr,
Julian Wiedmann00c163f2017-12-20 20:11:02 +01002288 .ndo_set_rx_mode = qeth_l3_set_rx_mode,
Julian Wiedmann942d6982017-04-11 16:11:10 +02002289 .ndo_do_ioctl = qeth_do_ioctl,
Thomas Richter8f43fb02016-06-16 16:18:59 +02002290 .ndo_fix_features = qeth_fix_features,
2291 .ndo_set_features = qeth_set_features,
Frank Blaschka8403b132009-01-08 10:50:55 -08002292 .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
2293 .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00002294 .ndo_tx_timeout = qeth_tx_timeout,
Frank Blaschka8403b132009-01-08 10:50:55 -08002295};
2296
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002297static const struct net_device_ops qeth_l3_osa_netdev_ops = {
2298 .ndo_open = qeth_l3_open,
2299 .ndo_stop = qeth_l3_stop,
2300 .ndo_get_stats = qeth_get_stats,
2301 .ndo_start_xmit = qeth_l3_hard_start_xmit,
Julian Wiedmannf13ade12018-09-17 17:35:56 +02002302 .ndo_features_check = qeth_l3_osa_features_check,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002303 .ndo_validate_addr = eth_validate_addr,
Julian Wiedmann00c163f2017-12-20 20:11:02 +01002304 .ndo_set_rx_mode = qeth_l3_set_rx_mode,
Julian Wiedmann942d6982017-04-11 16:11:10 +02002305 .ndo_do_ioctl = qeth_do_ioctl,
Thomas Richter8f43fb02016-06-16 16:18:59 +02002306 .ndo_fix_features = qeth_fix_features,
2307 .ndo_set_features = qeth_set_features,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002308 .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
2309 .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00002310 .ndo_tx_timeout = qeth_tx_timeout,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002311 .ndo_neigh_setup = qeth_l3_neigh_setup,
2312};
2313
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002314static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002315{
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002316 unsigned int headroom;
Thomas Richter1aec42b2015-01-21 13:39:10 +01002317 int rc;
2318
Julian Wiedmann30356d02018-11-02 19:04:10 +01002319 if (qeth_netdev_is_registered(card->dev))
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002320 return 0;
2321
Ursula Braun5113fec2010-05-16 21:15:14 +00002322 if (card->info.type == QETH_CARD_TYPE_OSD ||
2323 card->info.type == QETH_CARD_TYPE_OSX) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01002324 if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
2325 (card->info.link_type == QETH_LINK_TYPE_HSTR)) {
Paul Gortmaker1abd2292012-05-10 15:50:52 -04002326 pr_info("qeth_l3: ignoring TR device\n");
2327 return -ENODEV;
Kittipon Meesompop1b811432018-04-26 09:42:16 +02002328 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002329
Kittipon Meesompop1b811432018-04-26 09:42:16 +02002330 card->dev->netdev_ops = &qeth_l3_osa_netdev_ops;
Julian Wiedmann0f342942018-03-09 18:12:54 +01002331
Kittipon Meesompop1b811432018-04-26 09:42:16 +02002332 /*IPv6 address autoconfiguration stuff*/
2333 qeth_l3_get_unique_id(card);
2334 if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
2335 card->dev->dev_id = card->info.unique_id & 0xffff;
Julian Wiedmann0f342942018-03-09 18:12:54 +01002336
Kittipon Meesompop1b811432018-04-26 09:42:16 +02002337 if (!card->info.guestlan) {
2338 card->dev->features |= NETIF_F_SG;
2339 card->dev->hw_features |= NETIF_F_TSO |
2340 NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
2341 card->dev->vlan_features |= NETIF_F_TSO |
2342 NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002343 }
Kittipon Meesompop571f9dd82018-04-26 09:42:22 +02002344
2345 if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) {
2346 card->dev->hw_features |= NETIF_F_IPV6_CSUM;
2347 card->dev->vlan_features |= NETIF_F_IPV6_CSUM;
2348 }
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002349 if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
2350 card->dev->hw_features |= NETIF_F_TSO6;
2351 card->dev->vlan_features |= NETIF_F_TSO6;
2352 }
2353
2354 /* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */
2355 if (card->dev->hw_features & NETIF_F_TSO6)
2356 headroom = sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
2357 else if (card->dev->hw_features & NETIF_F_TSO)
2358 headroom = sizeof(struct qeth_hdr_tso);
2359 else
2360 headroom = sizeof(struct qeth_hdr) + VLAN_HLEN;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002361 } else if (card->info.type == QETH_CARD_TYPE_IQD) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01002362 card->dev->flags |= IFF_NOARP;
Frank Blaschka3d58cef2009-01-09 03:44:00 +00002363 card->dev->netdev_ops = &qeth_l3_netdev_ops;
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002364 headroom = sizeof(struct qeth_hdr) - ETH_HLEN;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002365
Thomas Richter1aec42b2015-01-21 13:39:10 +01002366 rc = qeth_l3_iqd_read_initial_mac(card);
2367 if (rc)
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002368 goto out;
2369
Frank Blaschkab3332932011-08-08 01:33:59 +00002370 if (card->options.hsuid[0])
2371 memcpy(card->dev->perm_addr, card->options.hsuid, 9);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002372 } else
2373 return -ENODEV;
2374
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002375 card->dev->needed_headroom = headroom;
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +00002376 card->dev->ethtool_ops = &qeth_l3_ethtool_ops;
Patrick McHardyf6469682013-04-19 02:04:27 +00002377 card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
2378 NETIF_F_HW_VLAN_CTAG_RX |
2379 NETIF_F_HW_VLAN_CTAG_FILTER;
Julian Wiedmanna647a022018-07-11 17:42:46 +02002380
Eric Dumazet02875872014-10-05 18:38:35 -07002381 netif_keep_dst(card->dev);
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02002382 if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6))
Julian Wiedmann371a1e72018-07-11 17:42:44 +02002383 netif_set_gso_max_size(card->dev,
2384 PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS(card) - 1));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002385
Julian Wiedmannd73ef322017-04-11 16:11:11 +02002386 netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002387 rc = register_netdev(card->dev);
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002388 if (!rc && carrier_ok)
2389 netif_carrier_on(card->dev);
2390
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002391out:
2392 if (rc)
2393 card->dev->netdev_ops = NULL;
2394 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002395}
2396
Ursula Braun79a04e42017-06-06 14:33:49 +02002397static const struct device_type qeth_l3_devtype = {
2398 .name = "qeth_layer3",
2399 .groups = qeth_l3_attr_groups,
2400};
2401
Frank Blaschka4a71df52008-02-15 09:19:42 +01002402static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
2403{
2404 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
Ursula Braun9111e782017-05-10 19:07:51 +02002405 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002406
Ursula Braun79a04e42017-06-06 14:33:49 +02002407 if (gdev->dev.type == &qeth_generic_devtype) {
2408 rc = qeth_l3_create_device_attributes(&gdev->dev);
2409 if (rc)
2410 return rc;
2411 }
Ursula Braunebccc7392017-05-10 19:07:54 +02002412 hash_init(card->ip_htable);
2413 hash_init(card->ip_mc_htable);
Frank Blaschka1da74b12011-05-12 18:45:02 +00002414 card->info.hwtrap = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002415 return 0;
2416}
2417
2418static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
2419{
2420 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
2421
Ursula Braun79a04e42017-06-06 14:33:49 +02002422 if (cgdev->dev.type == &qeth_generic_devtype)
2423 qeth_l3_remove_device_attributes(&cgdev->dev);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002424
Ursula Braunf2148562009-05-19 21:38:37 +00002425 qeth_set_allowed_threads(card, 0, 1);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002426 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
2427
Ursula Braun70919e22011-02-26 22:41:36 -08002428 if (cgdev->state == CCWGROUP_ONLINE)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002429 qeth_l3_set_offline(cgdev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002430
Julian Wiedmann30356d02018-11-02 19:04:10 +01002431 if (qeth_netdev_is_registered(card->dev))
2432 unregister_netdev(card->dev);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02002433 qeth_l3_clear_ip_htable(card, 0);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002434 qeth_l3_clear_ipato_list(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002435}
2436
2437static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
2438{
2439 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
2440 int rc = 0;
2441 enum qeth_card_states recover_flag;
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002442 bool carrier_ok;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002443
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002444 mutex_lock(&card->discipline_mutex);
Frank Blaschkac4949f02010-05-11 19:34:47 +00002445 mutex_lock(&card->conf_mutex);
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002446 QETH_DBF_TEXT(SETUP, 2, "setonlin");
2447 QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002448
Frank Blaschka4a71df52008-02-15 09:19:42 +01002449 recover_flag = card->state;
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002450 rc = qeth_core_hardsetup_card(card, &carrier_ok);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002451 if (rc) {
Thomas Richter1aec42b2015-01-21 13:39:10 +01002452 QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
Ursula Braunaa909222009-11-12 00:11:43 +00002453 rc = -ENODEV;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002454 goto out_remove;
2455 }
2456
Julian Wiedmann9fae5c32018-11-02 19:04:11 +01002457 rc = qeth_l3_setup_netdev(card, carrier_ok);
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002458 if (rc)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002459 goto out_remove;
2460
Frank Blaschka1da74b12011-05-12 18:45:02 +00002461 if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
2462 if (card->info.hwtrap &&
2463 qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))
2464 card->info.hwtrap = 0;
2465 } else
2466 card->info.hwtrap = 0;
2467
Frank Blaschka4a71df52008-02-15 09:19:42 +01002468 card->state = CARD_STATE_HARDSETUP;
2469 qeth_print_status_message(card);
2470
2471 /* softsetup */
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002472 QETH_DBF_TEXT(SETUP, 2, "softsetp");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002473
Frank Blaschka4a71df52008-02-15 09:19:42 +01002474 rc = qeth_l3_setadapter_parms(card);
2475 if (rc)
Thomas Richter1aec42b2015-01-21 13:39:10 +01002476 QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002477 if (!card->options.sniffer) {
2478 rc = qeth_l3_start_ipassists(card);
Stefan Raspl0f547612013-01-21 02:30:20 +00002479 if (rc) {
Ursula Braun76b11f82010-01-11 02:50:50 +00002480 QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
Stefan Raspl0f547612013-01-21 02:30:20 +00002481 goto out_remove;
2482 }
Ursula Braun76b11f82010-01-11 02:50:50 +00002483 rc = qeth_l3_setrouting_v4(card);
2484 if (rc)
Thomas Richter1aec42b2015-01-21 13:39:10 +01002485 QETH_DBF_TEXT_(SETUP, 2, "4err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002486 rc = qeth_l3_setrouting_v6(card);
2487 if (rc)
Thomas Richter1aec42b2015-01-21 13:39:10 +01002488 QETH_DBF_TEXT_(SETUP, 2, "5err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002489 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002490 netif_tx_disable(card->dev);
2491
2492 rc = qeth_init_qdio_queues(card);
2493 if (rc) {
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002494 QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
Ursula Braunaa909222009-11-12 00:11:43 +00002495 rc = -ENODEV;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002496 goto out_remove;
2497 }
2498 card->state = CARD_STATE_SOFTSETUP;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002499
2500 qeth_set_allowed_threads(card, 0xffffffff, 0);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02002501 qeth_l3_recover_ip(card);
Julian Wiedmannd025da92018-06-29 19:45:54 +02002502
2503 qeth_enable_hw_features(card->dev);
Frank Blaschka8af7c5a2008-04-24 10:15:25 +02002504 if (recover_flag == CARD_STATE_RECOVER) {
Ursula Braun4763b0a2011-12-19 22:56:32 +00002505 rtnl_lock();
Julian Wiedmann9aa17df2018-07-11 17:42:40 +02002506 if (recovery_mode) {
Ursula Braun39423442011-01-12 20:42:24 +00002507 __qeth_l3_open(card->dev);
Julian Wiedmann9aa17df2018-07-11 17:42:40 +02002508 qeth_l3_set_rx_mode(card->dev);
2509 } else {
Frank Blaschka8af7c5a2008-04-24 10:15:25 +02002510 dev_open(card->dev);
Julian Wiedmann9aa17df2018-07-11 17:42:40 +02002511 }
Ursula Braun4763b0a2011-12-19 22:56:32 +00002512 rtnl_unlock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002513 }
Stefan Raspl82f77cf2013-03-18 20:04:42 +00002514 qeth_trace_features(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002515 /* let user_space know that device is online */
2516 kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
Frank Blaschkac4949f02010-05-11 19:34:47 +00002517 mutex_unlock(&card->conf_mutex);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002518 mutex_unlock(&card->discipline_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002519 return 0;
2520out_remove:
Frank Blaschka4a71df52008-02-15 09:19:42 +01002521 qeth_l3_stop_card(card, 0);
2522 ccw_device_set_offline(CARD_DDEV(card));
2523 ccw_device_set_offline(CARD_WDEV(card));
2524 ccw_device_set_offline(CARD_RDEV(card));
Ursula Braun22ae2792014-02-24 13:12:06 +01002525 qdio_free(CARD_DDEV(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002526 if (recover_flag == CARD_STATE_RECOVER)
2527 card->state = CARD_STATE_RECOVER;
2528 else
2529 card->state = CARD_STATE_DOWN;
Frank Blaschkac4949f02010-05-11 19:34:47 +00002530 mutex_unlock(&card->conf_mutex);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002531 mutex_unlock(&card->discipline_mutex);
Ursula Braunaa909222009-11-12 00:11:43 +00002532 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002533}
2534
2535static int qeth_l3_set_online(struct ccwgroup_device *gdev)
2536{
2537 return __qeth_l3_set_online(gdev, 0);
2538}
2539
2540static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
2541 int recovery_mode)
2542{
2543 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
2544 int rc = 0, rc2 = 0, rc3 = 0;
2545 enum qeth_card_states recover_flag;
2546
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002547 mutex_lock(&card->discipline_mutex);
Frank Blaschkac4949f02010-05-11 19:34:47 +00002548 mutex_lock(&card->conf_mutex);
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002549 QETH_DBF_TEXT(SETUP, 3, "setoffl");
2550 QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002551
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002552 netif_carrier_off(card->dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002553 recover_flag = card->state;
Frank Blaschka1da74b12011-05-12 18:45:02 +00002554 if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
2555 qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
2556 card->info.hwtrap = 1;
2557 }
Ursula Braun0f5623c2008-10-24 11:16:52 +02002558 qeth_l3_stop_card(card, recovery_mode);
Einar Lueck72861ae2011-12-19 22:56:36 +00002559 if ((card->options.cq == QETH_CQ_ENABLED) && card->dev) {
2560 rtnl_lock();
2561 call_netdevice_notifiers(NETDEV_REBOOT, card->dev);
2562 rtnl_unlock();
2563 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002564 rc = ccw_device_set_offline(CARD_DDEV(card));
2565 rc2 = ccw_device_set_offline(CARD_WDEV(card));
2566 rc3 = ccw_device_set_offline(CARD_RDEV(card));
2567 if (!rc)
2568 rc = (rc2) ? rc2 : rc3;
2569 if (rc)
Peter Tiedemannd11ba0c2008-04-01 10:26:58 +02002570 QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
Ursula Braun22ae2792014-02-24 13:12:06 +01002571 qdio_free(CARD_DDEV(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002572 if (recover_flag == CARD_STATE_UP)
2573 card->state = CARD_STATE_RECOVER;
2574 /* let user_space know that device is offline */
2575 kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
Frank Blaschkac4949f02010-05-11 19:34:47 +00002576 mutex_unlock(&card->conf_mutex);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00002577 mutex_unlock(&card->discipline_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002578 return 0;
2579}
2580
2581static int qeth_l3_set_offline(struct ccwgroup_device *cgdev)
2582{
2583 return __qeth_l3_set_offline(cgdev, 0);
2584}
2585
2586static int qeth_l3_recover(void *ptr)
2587{
2588 struct qeth_card *card;
2589 int rc = 0;
2590
2591 card = (struct qeth_card *) ptr;
Carsten Otte847a50f2010-06-21 22:57:05 +00002592 QETH_CARD_TEXT(card, 2, "recover1");
2593 QETH_CARD_HEX(card, 2, &card, sizeof(void *));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002594 if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
2595 return 0;
Carsten Otte847a50f2010-06-21 22:57:05 +00002596 QETH_CARD_TEXT(card, 2, "recover2");
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002597 dev_warn(&card->gdev->dev,
2598 "A recovery process has been started for the device\n");
Stefan Raspl65d80132013-04-07 22:19:27 +00002599 qeth_set_recovery_task(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002600 __qeth_l3_set_offline(card->gdev, 1);
2601 rc = __qeth_l3_set_online(card->gdev, 1);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002602 if (!rc)
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002603 dev_info(&card->gdev->dev,
2604 "Device successfully recovered!\n");
Ursula Braun28a7e4c2008-09-19 12:56:03 +02002605 else {
Stefan Raspl0f547612013-01-21 02:30:20 +00002606 qeth_close_dev(card);
2607 dev_warn(&card->gdev->dev, "The qeth device driver "
Stefan Raspl2efaf5f2012-10-15 19:21:18 +00002608 "failed to recover an error on the device\n");
Ursula Braun28a7e4c2008-09-19 12:56:03 +02002609 }
Stefan Raspl65d80132013-04-07 22:19:27 +00002610 qeth_clear_recovery_task(card);
Frank Blaschkaa1c3ed42010-09-07 21:14:42 +00002611 qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
2612 qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002613 return 0;
2614}
2615
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002616static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
2617{
2618 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
2619
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002620 netif_device_detach(card->dev);
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002621 qeth_set_allowed_threads(card, 0, 1);
2622 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
2623 if (gdev->state == CCWGROUP_OFFLINE)
2624 return 0;
2625 if (card->state == CARD_STATE_UP) {
Frank Blaschka1da74b12011-05-12 18:45:02 +00002626 if (card->info.hwtrap)
2627 qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002628 __qeth_l3_set_offline(card->gdev, 1);
2629 } else
2630 __qeth_l3_set_offline(card->gdev, 0);
2631 return 0;
2632}
2633
2634static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
2635{
2636 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
2637 int rc = 0;
2638
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002639 if (card->state == CARD_STATE_RECOVER) {
2640 rc = __qeth_l3_set_online(card->gdev, 1);
2641 if (rc) {
Ursula Braun869da902010-03-08 20:36:56 +00002642 rtnl_lock();
2643 dev_close(card->dev);
2644 rtnl_unlock();
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002645 }
2646 } else
2647 rc = __qeth_l3_set_online(card->gdev, 0);
Julian Wiedmann6585ac42018-09-26 18:29:12 +02002648
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002649 qeth_set_allowed_threads(card, 0xffffffff, 0);
Julian Wiedmannd3d1b202018-07-19 12:43:51 +02002650 netif_device_attach(card->dev);
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002651 if (rc)
2652 dev_warn(&card->gdev->dev, "The qeth device driver "
2653 "failed to recover an error on the device\n");
2654 return rc;
2655}
2656
Eugene Crosserc044dc22014-01-29 09:23:48 +01002657/* Returns zero if the command is successfully "consumed" */
2658static int qeth_l3_control_event(struct qeth_card *card,
2659 struct qeth_ipa_cmd *cmd)
2660{
2661 return 1;
2662}
2663
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002664struct qeth_discipline qeth_l3_discipline = {
Ursula Braun79a04e42017-06-06 14:33:49 +02002665 .devtype = &qeth_l3_devtype,
Julian Wiedmannd73ef322017-04-11 16:11:11 +02002666 .process_rx_buffer = qeth_l3_process_inbound_buffer,
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002667 .recover = qeth_l3_recover,
2668 .setup = qeth_l3_probe_device,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002669 .remove = qeth_l3_remove_device,
2670 .set_online = qeth_l3_set_online,
2671 .set_offline = qeth_l3_set_offline,
Frank Blaschkabbcfcdc2009-06-16 10:30:31 +02002672 .freeze = qeth_l3_pm_suspend,
2673 .thaw = qeth_l3_pm_resume,
2674 .restore = qeth_l3_pm_resume,
Julian Wiedmann942d6982017-04-11 16:11:10 +02002675 .do_ioctl = qeth_l3_do_ioctl,
Eugene Crosserc044dc22014-01-29 09:23:48 +01002676 .control_event_handler = qeth_l3_control_event,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002677};
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002678EXPORT_SYMBOL_GPL(qeth_l3_discipline);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002679
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002680static int qeth_l3_handle_ip_event(struct qeth_card *card,
2681 struct qeth_ipaddr *addr,
2682 unsigned long event)
2683{
2684 switch (event) {
2685 case NETDEV_UP:
2686 spin_lock_bh(&card->ip_lock);
2687 qeth_l3_add_ip(card, addr);
2688 spin_unlock_bh(&card->ip_lock);
2689 return NOTIFY_OK;
2690 case NETDEV_DOWN:
2691 spin_lock_bh(&card->ip_lock);
2692 qeth_l3_delete_ip(card, addr);
2693 spin_unlock_bh(&card->ip_lock);
2694 return NOTIFY_OK;
2695 default:
2696 return NOTIFY_DONE;
2697 }
2698}
2699
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002700static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev)
2701{
2702 if (is_vlan_dev(dev))
2703 dev = vlan_dev_real_dev(dev);
2704 if (dev->netdev_ops == &qeth_l3_osa_netdev_ops ||
2705 dev->netdev_ops == &qeth_l3_netdev_ops)
2706 return (struct qeth_card *) dev->ml_priv;
2707 return NULL;
2708}
2709
Frank Blaschka4a71df52008-02-15 09:19:42 +01002710static int qeth_l3_ip_event(struct notifier_block *this,
David S. Miller76fef2b2008-03-22 18:22:42 -07002711 unsigned long event, void *ptr)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002712{
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02002713
Frank Blaschka4a71df52008-02-15 09:19:42 +01002714 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002715 struct net_device *dev = ifa->ifa_dev->dev;
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002716 struct qeth_ipaddr addr;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002717 struct qeth_card *card;
2718
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002719 if (dev_net(dev) != &init_net)
David S. Miller76fef2b2008-03-22 18:22:42 -07002720 return NOTIFY_DONE;
2721
Frank Blaschka4a71df52008-02-15 09:19:42 +01002722 card = qeth_l3_get_card_from_dev(dev);
2723 if (!card)
2724 return NOTIFY_DONE;
frank.blaschka@de.ibm.com6d8823d2012-05-16 01:28:26 +00002725 QETH_CARD_TEXT(card, 3, "ipevent");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002726
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002727 qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV4);
2728 addr.u.a4.addr = be32_to_cpu(ifa->ifa_address);
2729 addr.u.a4.mask = be32_to_cpu(ifa->ifa_mask);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002730
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002731 return qeth_l3_handle_ip_event(card, &addr, event);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002732}
2733
2734static struct notifier_block qeth_l3_ip_notifier = {
2735 qeth_l3_ip_event,
2736 NULL,
2737};
2738
Frank Blaschka4a71df52008-02-15 09:19:42 +01002739static int qeth_l3_ip6_event(struct notifier_block *this,
David S. Miller76fef2b2008-03-22 18:22:42 -07002740 unsigned long event, void *ptr)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002741{
2742 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002743 struct net_device *dev = ifa->idev->dev;
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002744 struct qeth_ipaddr addr;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002745 struct qeth_card *card;
2746
Frank Blaschka4a71df52008-02-15 09:19:42 +01002747 card = qeth_l3_get_card_from_dev(dev);
2748 if (!card)
2749 return NOTIFY_DONE;
Carsten Otte847a50f2010-06-21 22:57:05 +00002750 QETH_CARD_TEXT(card, 3, "ip6event");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002751 if (!qeth_is_supported(card, IPA_IPV6))
2752 return NOTIFY_DONE;
2753
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002754 qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6);
2755 addr.u.a6.addr = ifa->addr;
2756 addr.u.a6.pfxlen = ifa->prefix_len;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002757
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002758 return qeth_l3_handle_ip_event(card, &addr, event);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002759}
2760
2761static struct notifier_block qeth_l3_ip6_notifier = {
2762 qeth_l3_ip6_event,
2763 NULL,
2764};
Frank Blaschka4a71df52008-02-15 09:19:42 +01002765
2766static int qeth_l3_register_notifiers(void)
2767{
2768 int rc;
2769
Carsten Otte847a50f2010-06-21 22:57:05 +00002770 QETH_DBF_TEXT(SETUP, 5, "regnotif");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002771 rc = register_inetaddr_notifier(&qeth_l3_ip_notifier);
2772 if (rc)
2773 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002774 rc = register_inet6addr_notifier(&qeth_l3_ip6_notifier);
2775 if (rc) {
2776 unregister_inetaddr_notifier(&qeth_l3_ip_notifier);
2777 return rc;
2778 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002779 return 0;
2780}
2781
2782static void qeth_l3_unregister_notifiers(void)
2783{
Carsten Otte847a50f2010-06-21 22:57:05 +00002784 QETH_DBF_TEXT(SETUP, 5, "unregnot");
Stefan Raspl18af5c12012-11-19 02:46:50 +00002785 WARN_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier));
Stefan Raspl18af5c12012-11-19 02:46:50 +00002786 WARN_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002787}
2788
2789static int __init qeth_l3_init(void)
2790{
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002791 pr_info("register layer 3 discipline\n");
Julian Wiedmannc0622042017-12-20 20:10:58 +01002792 return qeth_l3_register_notifiers();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002793}
2794
2795static void __exit qeth_l3_exit(void)
2796{
2797 qeth_l3_unregister_notifiers();
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002798 pr_info("unregister layer 3 discipline\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002799}
2800
2801module_init(qeth_l3_init);
2802module_exit(qeth_l3_exit);
2803MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
2804MODULE_DESCRIPTION("qeth layer 3 discipline");
2805MODULE_LICENSE("GPL");