blob: a6f8878b55c6a9324cc8ef5cf01d23f9f94fe222 [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>
Frank Blaschkab3332932011-08-08 01:33:59 +000035#include <net/iucv/af_iucv.h>
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +020036#include <linux/hashtable.h>
Frank Blaschka4a71df52008-02-15 09:19:42 +010037
Frank Blaschka4a71df52008-02-15 09:19:42 +010038#include "qeth_l3.h"
Frank Blaschka4a71df52008-02-15 09:19:42 +010039
Frank Blaschka4a71df52008-02-15 09:19:42 +010040static int qeth_l3_register_addr_entry(struct qeth_card *,
41 struct qeth_ipaddr *);
42static int qeth_l3_deregister_addr_entry(struct qeth_card *,
43 struct qeth_ipaddr *);
Frank Blaschka4a71df52008-02-15 09:19:42 +010044
Julian Wiedmanne6b1b7d2019-12-18 17:34:44 +010045int qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const u8 *addr,
46 char *buf)
Frank Blaschka4a71df52008-02-15 09:19:42 +010047{
48 if (proto == QETH_PROT_IPV4)
Julian Wiedmanne6b1b7d2019-12-18 17:34:44 +010049 return sprintf(buf, "%pI4", addr);
50 else
51 return sprintf(buf, "%pI6", addr);
Frank Blaschka4a71df52008-02-15 09:19:42 +010052}
53
Julian Wiedmannc5c48c52018-02-27 18:58:16 +010054static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card,
55 struct qeth_ipaddr *query)
56{
Julian Wiedmann1b40d4b2019-10-31 13:42:20 +010057 u32 key = qeth_l3_ipaddr_hash(query);
Julian Wiedmannc5c48c52018-02-27 18:58:16 +010058 struct qeth_ipaddr *addr;
59
60 if (query->is_multicast) {
Julian Wiedmann09732922020-07-14 16:23:04 +020061 hash_for_each_possible(card->rx_mode_addrs, addr, hnode, key)
Julian Wiedmannc5c48c52018-02-27 18:58:16 +010062 if (qeth_l3_addr_match_ip(addr, query))
63 return addr;
64 } else {
65 hash_for_each_possible(card->ip_htable, addr, hnode, key)
66 if (qeth_l3_addr_match_ip(addr, query))
67 return addr;
68 }
69 return NULL;
70}
71
Frank Blaschka4a71df52008-02-15 09:19:42 +010072static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
73{
74 int i, j;
75 u8 octet;
76
77 for (i = 0; i < len; ++i) {
78 octet = addr[i];
79 for (j = 7; j >= 0; --j) {
80 bits[i*8 + j] = octet & 1;
81 octet >>= 1;
82 }
83 }
84}
85
Julian Wiedmann02f510f2017-12-13 18:56:32 +010086static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
87 struct qeth_ipaddr *addr)
Frank Blaschka4a71df52008-02-15 09:19:42 +010088{
89 struct qeth_ipato_entry *ipatoe;
90 u8 addr_bits[128] = {0, };
91 u8 ipatoe_bits[128] = {0, };
92 int rc = 0;
93
94 if (!card->ipato.enabled)
Gustavo A. R. Silva1a363b02018-08-09 14:48:04 +020095 return false;
Julian Wiedmannb22d73d62017-12-13 18:56:30 +010096 if (addr->type != QETH_IP_TYPE_NORMAL)
Gustavo A. R. Silva1a363b02018-08-09 14:48:04 +020097 return false;
Frank Blaschka4a71df52008-02-15 09:19:42 +010098
99 qeth_l3_convert_addr_to_bits((u8 *) &addr->u, addr_bits,
100 (addr->proto == QETH_PROT_IPV4)? 4:16);
101 list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
102 if (addr->proto != ipatoe->proto)
103 continue;
104 qeth_l3_convert_addr_to_bits(ipatoe->addr, ipatoe_bits,
105 (ipatoe->proto == QETH_PROT_IPV4) ?
106 4 : 16);
107 if (addr->proto == QETH_PROT_IPV4)
Julian Wiedmannab29c482020-09-23 10:36:55 +0200108 rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100109 else
Julian Wiedmannab29c482020-09-23 10:36:55 +0200110 rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100111 if (rc)
112 break;
113 }
114 /* invert? */
115 if ((addr->proto == QETH_PROT_IPV4) && card->ipato.invert4)
116 rc = !rc;
117 else if ((addr->proto == QETH_PROT_IPV6) && card->ipato.invert6)
118 rc = !rc;
119
120 return rc;
121}
122
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100123static int qeth_l3_delete_ip(struct qeth_card *card,
124 struct qeth_ipaddr *tmp_addr)
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200125{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100126 int rc = 0;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200127 struct qeth_ipaddr *addr;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100128
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100129 if (tmp_addr->type == QETH_IP_TYPE_RXIP)
130 QETH_CARD_TEXT(card, 2, "delrxip");
131 else if (tmp_addr->type == QETH_IP_TYPE_VIPA)
132 QETH_CARD_TEXT(card, 2, "delvipa");
133 else
134 QETH_CARD_TEXT(card, 2, "delip");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100135
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200136 if (tmp_addr->proto == QETH_PROT_IPV4)
137 QETH_CARD_HEX(card, 4, &tmp_addr->u.a4.addr, 4);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100138 else {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200139 QETH_CARD_HEX(card, 4, &tmp_addr->u.a6.addr, 8);
140 QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100141 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200142
Julian Wiedmannc5c48c52018-02-27 18:58:16 +0100143 addr = qeth_l3_find_addr_by_ip(card, tmp_addr);
144 if (!addr || !qeth_l3_addr_match_all(addr, tmp_addr))
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200145 return -ENOENT;
146
147 addr->ref_counter--;
Julian Wiedmann4964c662018-02-27 18:58:15 +0100148 if (addr->type == QETH_IP_TYPE_NORMAL && addr->ref_counter > 0)
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200149 return rc;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200150
Julian Wiedmann98d823a2018-02-27 18:58:13 +0100151 if (qeth_card_hw_is_reachable(card))
152 rc = qeth_l3_deregister_addr_entry(card, addr);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200153
154 hash_del(&addr->hnode);
155 kfree(addr);
156
Frank Blaschka4a71df52008-02-15 09:19:42 +0100157 return rc;
158}
159
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100160static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100161{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100162 int rc = 0;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200163 struct qeth_ipaddr *addr;
Julian Wiedmannc5c48c52018-02-27 18:58:16 +0100164 char buf[40];
Frank Blaschka4a71df52008-02-15 09:19:42 +0100165
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100166 if (tmp_addr->type == QETH_IP_TYPE_RXIP)
167 QETH_CARD_TEXT(card, 2, "addrxip");
168 else if (tmp_addr->type == QETH_IP_TYPE_VIPA)
169 QETH_CARD_TEXT(card, 2, "addvipa");
170 else
171 QETH_CARD_TEXT(card, 2, "addip");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200172
173 if (tmp_addr->proto == QETH_PROT_IPV4)
174 QETH_CARD_HEX(card, 4, &tmp_addr->u.a4.addr, 4);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100175 else {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200176 QETH_CARD_HEX(card, 4, &tmp_addr->u.a6.addr, 8);
177 QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100178 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200179
Julian Wiedmannc5c48c52018-02-27 18:58:16 +0100180 addr = qeth_l3_find_addr_by_ip(card, tmp_addr);
181 if (addr) {
182 if (tmp_addr->type != QETH_IP_TYPE_NORMAL)
183 return -EADDRINUSE;
184 if (qeth_l3_addr_match_all(addr, tmp_addr)) {
185 addr->ref_counter++;
186 return 0;
187 }
188 qeth_l3_ipaddr_to_string(tmp_addr->proto, (u8 *)&tmp_addr->u,
189 buf);
190 dev_warn(&card->gdev->dev,
191 "Registering IP address %s failed\n", buf);
192 return -EADDRINUSE;
193 } else {
Julian Wiedmannb80c08a2019-11-14 11:19:23 +0100194 addr = kmemdup(tmp_addr, sizeof(*tmp_addr), GFP_KERNEL);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200195 if (!addr)
196 return -ENOMEM;
197
Julian Wiedmannb22d73d62017-12-13 18:56:30 +0100198 if (qeth_l3_is_addr_covered_by_ipato(card, addr)) {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200199 QETH_CARD_TEXT(card, 2, "tkovaddr");
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100200 addr->ipato = 1;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200201 }
202 hash_add(card->ip_htable, &addr->hnode,
203 qeth_l3_ipaddr_hash(addr));
204
Ursula Brauna7531c12016-09-15 14:39:23 +0200205 if (!qeth_card_hw_is_reachable(card)) {
206 addr->disp_flag = QETH_DISP_ADDR_ADD;
207 return 0;
208 }
209
Julian Wiedmannadee2592019-12-18 17:34:48 +0100210 rc = qeth_l3_register_addr_entry(card, addr);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200211
Julian Wiedmann4b7ae122019-02-12 18:33:23 +0100212 if (!rc || rc == -EADDRINUSE || rc == -ENETDOWN) {
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200213 addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200214 } else {
215 hash_del(&addr->hnode);
216 kfree(addr);
217 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200218 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100219 return rc;
220}
221
Julian Wiedmann05a17852019-03-28 16:39:21 +0100222static int qeth_l3_modify_ip(struct qeth_card *card, struct qeth_ipaddr *addr,
223 bool add)
224{
225 int rc;
226
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100227 mutex_lock(&card->ip_lock);
Julian Wiedmann05a17852019-03-28 16:39:21 +0100228 rc = add ? qeth_l3_add_ip(card, addr) : qeth_l3_delete_ip(card, addr);
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100229 mutex_unlock(&card->ip_lock);
Julian Wiedmann05a17852019-03-28 16:39:21 +0100230
231 return rc;
232}
233
Julian Wiedmannd0c74822019-03-28 16:39:19 +0100234static void qeth_l3_drain_rx_mode_cache(struct qeth_card *card)
235{
236 struct qeth_ipaddr *addr;
237 struct hlist_node *tmp;
238 int i;
239
Julian Wiedmann09732922020-07-14 16:23:04 +0200240 hash_for_each_safe(card->rx_mode_addrs, i, tmp, addr, hnode) {
Julian Wiedmannd0c74822019-03-28 16:39:19 +0100241 hash_del(&addr->hnode);
242 kfree(addr);
243 }
Julian Wiedmannd0c74822019-03-28 16:39:19 +0100244}
245
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200246static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100247{
248 struct qeth_ipaddr *addr;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200249 struct hlist_node *tmp;
250 int i;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100251
Carsten Otte847a50f2010-06-21 22:57:05 +0000252 QETH_CARD_TEXT(card, 4, "clearip");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200253
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100254 mutex_lock(&card->ip_lock);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200255
256 hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) {
257 if (!recover) {
258 hash_del(&addr->hnode);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100259 kfree(addr);
260 continue;
261 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200262 addr->disp_flag = QETH_DISP_ADDR_ADD;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100263 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200264
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100265 mutex_unlock(&card->ip_lock);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100266}
Julian Wiedmannd0c74822019-03-28 16:39:19 +0100267
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200268static void qeth_l3_recover_ip(struct qeth_card *card)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100269{
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200270 struct qeth_ipaddr *addr;
271 struct hlist_node *tmp;
272 int i;
273 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100274
Ursula Brauna7531c12016-09-15 14:39:23 +0200275 QETH_CARD_TEXT(card, 4, "recovrip");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100276
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100277 mutex_lock(&card->ip_lock);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100278
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200279 hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) {
Julian Wiedmann98d823a2018-02-27 18:58:13 +0100280 if (addr->disp_flag == QETH_DISP_ADDR_ADD) {
Julian Wiedmannadee2592019-12-18 17:34:48 +0100281 rc = qeth_l3_register_addr_entry(card, addr);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200282
283 if (!rc) {
284 addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200285 } else {
286 hash_del(&addr->hnode);
287 kfree(addr);
288 }
289 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100290 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200291
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100292 mutex_unlock(&card->ip_lock);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100293}
294
Julian Wiedmann4b7ae122019-02-12 18:33:23 +0100295static int qeth_l3_setdelip_cb(struct qeth_card *card, struct qeth_reply *reply,
296 unsigned long data)
297{
298 struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
299
300 switch (cmd->hdr.return_code) {
301 case IPA_RC_SUCCESS:
302 return 0;
303 case IPA_RC_DUPLICATE_IP_ADDRESS:
304 return -EADDRINUSE;
305 case IPA_RC_MC_ADDR_NOT_FOUND:
306 return -ENOENT;
307 case IPA_RC_LAN_OFFLINE:
308 return -ENETDOWN;
309 default:
310 return -EIO;
311 }
312}
313
Frank Blaschka4a71df52008-02-15 09:19:42 +0100314static int qeth_l3_send_setdelmc(struct qeth_card *card,
Julian Wiedmannb14912e2020-08-27 10:16:58 +0200315 struct qeth_ipaddr *addr,
316 enum qeth_ipa_cmds ipacmd)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100317{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100318 struct qeth_cmd_buffer *iob;
319 struct qeth_ipa_cmd *cmd;
320
Carsten Otte847a50f2010-06-21 22:57:05 +0000321 QETH_CARD_TEXT(card, 4, "setdelmc");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100322
Julian Wiedmanna59d1212019-06-27 17:01:22 +0200323 iob = qeth_ipa_alloc_cmd(card, ipacmd, addr->proto,
324 IPA_DATA_SIZEOF(setdelipm));
Thomas Richter1aec42b2015-01-21 13:39:10 +0100325 if (!iob)
326 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +0100327 cmd = __ipa_cmd(iob);
Julian Wiedmann8bf70b62019-10-31 13:42:21 +0100328 if (addr->proto == QETH_PROT_IPV6) {
329 cmd->data.setdelipm.ip = addr->u.a6.addr;
330 ipv6_eth_mc_map(&addr->u.a6.addr, cmd->data.setdelipm.mac);
331 } else {
332 cmd->data.setdelipm.ip.s6_addr32[3] = addr->u.a4.addr;
333 ip_eth_mc_map(addr->u.a4.addr, cmd->data.setdelipm.mac);
334 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100335
Julian Wiedmann4b7ae122019-02-12 18:33:23 +0100336 return qeth_send_ipa_cmd(card, iob, qeth_l3_setdelip_cb, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100337}
338
Julian Wiedmann490df972019-12-18 17:34:46 +0100339static void qeth_l3_set_ipv6_prefix(struct in6_addr *prefix, unsigned int len)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100340{
Julian Wiedmann490df972019-12-18 17:34:46 +0100341 unsigned int i = 0;
342
343 while (len && i < 4) {
344 int mask_len = min_t(int, len, 32);
345
346 prefix->s6_addr32[i] = inet_make_mask(mask_len);
347 len -= mask_len;
348 i++;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100349 }
350}
351
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100352static u32 qeth_l3_get_setdelip_flags(struct qeth_ipaddr *addr, bool set)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100353{
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100354 switch (addr->type) {
355 case QETH_IP_TYPE_RXIP:
356 return (set) ? QETH_IPA_SETIP_TAKEOVER_FLAG : 0;
357 case QETH_IP_TYPE_VIPA:
358 return (set) ? QETH_IPA_SETIP_VIPA_FLAG :
359 QETH_IPA_DELIP_VIPA_FLAG;
360 default:
361 return (set && addr->ipato) ? QETH_IPA_SETIP_TAKEOVER_FLAG : 0;
362 }
363}
364
365static int qeth_l3_send_setdelip(struct qeth_card *card,
366 struct qeth_ipaddr *addr,
367 enum qeth_ipa_cmds ipacmd)
368{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100369 struct qeth_cmd_buffer *iob;
370 struct qeth_ipa_cmd *cmd;
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100371 u32 flags;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100372
Carsten Otte847a50f2010-06-21 22:57:05 +0000373 QETH_CARD_TEXT(card, 4, "setdelip");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100374
Julian Wiedmanna59d1212019-06-27 17:01:22 +0200375 iob = qeth_ipa_alloc_cmd(card, ipacmd, addr->proto,
376 IPA_DATA_SIZEOF(setdelip6));
Thomas Richter1aec42b2015-01-21 13:39:10 +0100377 if (!iob)
378 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +0100379 cmd = __ipa_cmd(iob);
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100380
381 flags = qeth_l3_get_setdelip_flags(addr, ipacmd == IPA_CMD_SETIP);
382 QETH_CARD_TEXT_(card, 4, "flags%02X", flags);
383
Frank Blaschka4a71df52008-02-15 09:19:42 +0100384 if (addr->proto == QETH_PROT_IPV6) {
Julian Wiedmann490df972019-12-18 17:34:46 +0100385 cmd->data.setdelip6.addr = addr->u.a6.addr;
386 qeth_l3_set_ipv6_prefix(&cmd->data.setdelip6.prefix,
387 addr->u.a6.pfxlen);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100388 cmd->data.setdelip6.flags = flags;
389 } else {
Julian Wiedmann490df972019-12-18 17:34:46 +0100390 cmd->data.setdelip4.addr = addr->u.a4.addr;
391 cmd->data.setdelip4.mask = addr->u.a4.mask;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100392 cmd->data.setdelip4.flags = flags;
393 }
394
Julian Wiedmann4b7ae122019-02-12 18:33:23 +0100395 return qeth_send_ipa_cmd(card, iob, qeth_l3_setdelip_cb, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100396}
397
398static int qeth_l3_send_setrouting(struct qeth_card *card,
399 enum qeth_routing_types type, enum qeth_prot_versions prot)
400{
401 int rc;
402 struct qeth_ipa_cmd *cmd;
403 struct qeth_cmd_buffer *iob;
404
Carsten Otte847a50f2010-06-21 22:57:05 +0000405 QETH_CARD_TEXT(card, 4, "setroutg");
Julian Wiedmanna59d1212019-06-27 17:01:22 +0200406 iob = qeth_ipa_alloc_cmd(card, IPA_CMD_SETRTG, prot,
407 IPA_DATA_SIZEOF(setrtg));
Thomas Richter1aec42b2015-01-21 13:39:10 +0100408 if (!iob)
409 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +0100410 cmd = __ipa_cmd(iob);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100411 cmd->data.setrtg.type = (type);
412 rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
413
414 return rc;
415}
416
Stefan Raspl82e2e782013-03-18 20:04:43 +0000417static int qeth_l3_correct_routing_type(struct qeth_card *card,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100418 enum qeth_routing_types *type, enum qeth_prot_versions prot)
419{
Julian Wiedmann379ac992019-04-25 18:25:57 +0200420 if (IS_IQD(card)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100421 switch (*type) {
422 case NO_ROUTER:
423 case PRIMARY_CONNECTOR:
424 case SECONDARY_CONNECTOR:
425 case MULTICAST_ROUTER:
Stefan Raspl82e2e782013-03-18 20:04:43 +0000426 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100427 default:
428 goto out_inval;
429 }
430 } else {
431 switch (*type) {
432 case NO_ROUTER:
433 case PRIMARY_ROUTER:
434 case SECONDARY_ROUTER:
Stefan Raspl82e2e782013-03-18 20:04:43 +0000435 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100436 case MULTICAST_ROUTER:
437 if (qeth_is_ipafunc_supported(card, prot,
438 IPA_OSA_MC_ROUTER))
Stefan Raspl82e2e782013-03-18 20:04:43 +0000439 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100440 default:
441 goto out_inval;
442 }
443 }
444out_inval:
Frank Blaschka4a71df52008-02-15 09:19:42 +0100445 *type = NO_ROUTER;
Stefan Raspl82e2e782013-03-18 20:04:43 +0000446 return -EINVAL;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100447}
448
449int qeth_l3_setrouting_v4(struct qeth_card *card)
450{
451 int rc;
452
Carsten Otte847a50f2010-06-21 22:57:05 +0000453 QETH_CARD_TEXT(card, 3, "setrtg4");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100454
Stefan Raspl82e2e782013-03-18 20:04:43 +0000455 rc = qeth_l3_correct_routing_type(card, &card->options.route4.type,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100456 QETH_PROT_IPV4);
Stefan Raspl82e2e782013-03-18 20:04:43 +0000457 if (rc)
458 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100459
460 rc = qeth_l3_send_setrouting(card, card->options.route4.type,
461 QETH_PROT_IPV4);
462 if (rc) {
463 card->options.route4.type = NO_ROUTER;
Julian Wiedmanne19e5be2018-11-02 19:04:08 +0100464 QETH_DBF_MESSAGE(2, "Error (%#06x) while setting routing type on device %x. Type set to 'no router'.\n",
465 rc, CARD_DEVID(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100466 }
467 return rc;
468}
469
470int qeth_l3_setrouting_v6(struct qeth_card *card)
471{
472 int rc = 0;
473
Carsten Otte847a50f2010-06-21 22:57:05 +0000474 QETH_CARD_TEXT(card, 3, "setrtg6");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100475
476 if (!qeth_is_supported(card, IPA_IPV6))
477 return 0;
Stefan Raspl82e2e782013-03-18 20:04:43 +0000478 rc = qeth_l3_correct_routing_type(card, &card->options.route6.type,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100479 QETH_PROT_IPV6);
Stefan Raspl82e2e782013-03-18 20:04:43 +0000480 if (rc)
481 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100482
483 rc = qeth_l3_send_setrouting(card, card->options.route6.type,
484 QETH_PROT_IPV6);
485 if (rc) {
486 card->options.route6.type = NO_ROUTER;
Julian Wiedmanne19e5be2018-11-02 19:04:08 +0100487 QETH_DBF_MESSAGE(2, "Error (%#06x) while setting routing type on device %x. Type set to 'no router'.\n",
488 rc, CARD_DEVID(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100489 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100490 return rc;
491}
492
493/*
494 * IP address takeover related functions
495 */
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100496
497/**
498 * qeth_l3_update_ipato() - Update 'takeover' property, for all NORMAL IPs.
499 *
500 * Caller must hold ip_lock.
501 */
502void qeth_l3_update_ipato(struct qeth_card *card)
503{
504 struct qeth_ipaddr *addr;
505 unsigned int i;
506
507 hash_for_each(card->ip_htable, i, addr, hnode) {
508 if (addr->type != QETH_IP_TYPE_NORMAL)
509 continue;
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100510 addr->ipato = qeth_l3_is_addr_covered_by_ipato(card, addr);
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100511 }
512}
513
Frank Blaschka4a71df52008-02-15 09:19:42 +0100514static void qeth_l3_clear_ipato_list(struct qeth_card *card)
515{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100516 struct qeth_ipato_entry *ipatoe, *tmp;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100517
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100518 mutex_lock(&card->ip_lock);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200519
Frank Blaschka4a71df52008-02-15 09:19:42 +0100520 list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
521 list_del(&ipatoe->entry);
522 kfree(ipatoe);
523 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200524
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100525 qeth_l3_update_ipato(card);
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100526 mutex_unlock(&card->ip_lock);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100527}
528
529int qeth_l3_add_ipato_entry(struct qeth_card *card,
530 struct qeth_ipato_entry *new)
531{
532 struct qeth_ipato_entry *ipatoe;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100533 int rc = 0;
534
Carsten Otte847a50f2010-06-21 22:57:05 +0000535 QETH_CARD_TEXT(card, 2, "addipato");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200536
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100537 mutex_lock(&card->ip_lock);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200538
Frank Blaschka4a71df52008-02-15 09:19:42 +0100539 list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
540 if (ipatoe->proto != new->proto)
541 continue;
542 if (!memcmp(ipatoe->addr, new->addr,
543 (ipatoe->proto == QETH_PROT_IPV4)? 4:16) &&
544 (ipatoe->mask_bits == new->mask_bits)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100545 rc = -EEXIST;
546 break;
547 }
548 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200549
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100550 if (!rc) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100551 list_add_tail(&new->entry, &card->ipato.entries);
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100552 qeth_l3_update_ipato(card);
553 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100554
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100555 mutex_unlock(&card->ip_lock);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200556
Frank Blaschka4a71df52008-02-15 09:19:42 +0100557 return rc;
558}
559
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100560int qeth_l3_del_ipato_entry(struct qeth_card *card,
561 enum qeth_prot_versions proto, u8 *addr,
Julian Wiedmannab29c482020-09-23 10:36:55 +0200562 unsigned int mask_bits)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100563{
564 struct qeth_ipato_entry *ipatoe, *tmp;
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100565 int rc = -ENOENT;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100566
Carsten Otte847a50f2010-06-21 22:57:05 +0000567 QETH_CARD_TEXT(card, 2, "delipato");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200568
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100569 mutex_lock(&card->ip_lock);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200570
Frank Blaschka4a71df52008-02-15 09:19:42 +0100571 list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
572 if (ipatoe->proto != proto)
573 continue;
574 if (!memcmp(ipatoe->addr, addr,
575 (proto == QETH_PROT_IPV4)? 4:16) &&
576 (ipatoe->mask_bits == mask_bits)) {
577 list_del(&ipatoe->entry);
Julian Wiedmann02f510f2017-12-13 18:56:32 +0100578 qeth_l3_update_ipato(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100579 kfree(ipatoe);
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100580 rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100581 }
582 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200583
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +0100584 mutex_unlock(&card->ip_lock);
Julian Wiedmann23901662019-12-18 17:34:45 +0100585
Julian Wiedmannb9ea5252017-12-27 17:44:28 +0100586 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100587}
588
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100589int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip,
590 enum qeth_ip_types type,
591 enum qeth_prot_versions proto)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100592{
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100593 struct qeth_ipaddr addr;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100594
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100595 qeth_l3_init_ipaddr(&addr, type, proto);
596 if (proto == QETH_PROT_IPV4)
597 memcpy(&addr.u.a4.addr, ip, 4);
598 else
599 memcpy(&addr.u.a6.addr, ip, 16);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200600
Julian Wiedmannf3380b12020-09-23 10:36:56 +0200601 return qeth_l3_modify_ip(card, &addr, add);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100602}
603
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100604int qeth_l3_modify_hsuid(struct qeth_card *card, bool add)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100605{
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100606 struct qeth_ipaddr addr;
Julian Wiedmann05a17852019-03-28 16:39:21 +0100607 unsigned int i;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100608
Julian Wiedmann1617dae2018-03-09 18:13:02 +0100609 qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6);
610 addr.u.a6.addr.s6_addr[0] = 0xfe;
611 addr.u.a6.addr.s6_addr[1] = 0x80;
612 for (i = 0; i < 8; i++)
613 addr.u.a6.addr.s6_addr[8+i] = card->options.hsuid[i];
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200614
Julian Wiedmann05a17852019-03-28 16:39:21 +0100615 return qeth_l3_modify_ip(card, &addr, add);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100616}
617
618static int qeth_l3_register_addr_entry(struct qeth_card *card,
619 struct qeth_ipaddr *addr)
620{
621 char buf[50];
622 int rc = 0;
623 int cnt = 3;
624
Julian Wiedmannbd74a7f2018-11-02 19:04:09 +0100625 if (card->options.sniffer)
626 return 0;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +0200627
Frank Blaschka4a71df52008-02-15 09:19:42 +0100628 if (addr->proto == QETH_PROT_IPV4) {
Carsten Otte847a50f2010-06-21 22:57:05 +0000629 QETH_CARD_TEXT(card, 2, "setaddr4");
630 QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100631 } else if (addr->proto == QETH_PROT_IPV6) {
Carsten Otte847a50f2010-06-21 22:57:05 +0000632 QETH_CARD_TEXT(card, 2, "setaddr6");
633 QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
634 QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100635 } else {
Carsten Otte847a50f2010-06-21 22:57:05 +0000636 QETH_CARD_TEXT(card, 2, "setaddr?");
637 QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100638 }
639 do {
640 if (addr->is_multicast)
641 rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_SETIPM);
642 else
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100643 rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_SETIP);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100644 if (rc)
Carsten Otte847a50f2010-06-21 22:57:05 +0000645 QETH_CARD_TEXT(card, 2, "failed");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100646 } while ((--cnt > 0) && rc);
647 if (rc) {
Carsten Otte847a50f2010-06-21 22:57:05 +0000648 QETH_CARD_TEXT(card, 2, "FAILED");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100649 qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100650 dev_warn(&card->gdev->dev,
651 "Registering IP address %s failed\n", buf);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100652 }
653 return rc;
654}
655
656static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
657 struct qeth_ipaddr *addr)
658{
659 int rc = 0;
660
Julian Wiedmannbd74a7f2018-11-02 19:04:09 +0100661 if (card->options.sniffer)
662 return 0;
663
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, "deladdr4");
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, "deladdr6");
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, "deladdr?");
673 QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100674 }
675 if (addr->is_multicast)
676 rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_DELIPM);
677 else
Julian Wiedmannb1d5e362018-03-09 18:13:03 +0100678 rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP);
Frank Blaschkac4cef072008-07-14 09:59:31 +0200679 if (rc)
Carsten Otte847a50f2010-06-21 22:57:05 +0000680 QETH_CARD_TEXT(card, 2, "failed");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100681
682 return rc;
683}
684
Frank Blaschka4a71df52008-02-15 09:19:42 +0100685static int qeth_l3_setadapter_parms(struct qeth_card *card)
686{
Julian Wiedmann699d3fe2017-08-15 17:02:41 +0200687 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100688
Julian Wiedmann57a688aa2019-06-11 18:37:55 +0200689 QETH_CARD_TEXT(card, 2, "setadprm");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100690
Frank Blaschka4a71df52008-02-15 09:19:42 +0100691 if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) {
692 rc = qeth_setadpparms_change_macaddr(card);
693 if (rc)
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100694 dev_warn(&card->gdev->dev, "Reading the adapter MAC"
Heiko Carstens6ea2fde2009-01-04 17:36:32 -0800695 " address failed\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100696 }
697
Frank Blaschka4a71df52008-02-15 09:19:42 +0100698 return rc;
699}
700
Frank Blaschka4a71df52008-02-15 09:19:42 +0100701static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card)
702{
703 int rc;
704
Carsten Otte847a50f2010-06-21 22:57:05 +0000705 QETH_CARD_TEXT(card, 3, "ipaarp");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100706
707 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100708 dev_info(&card->gdev->dev,
709 "ARP processing not supported on %s!\n",
710 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100711 return 0;
712 }
Thomas Richter4d7def22015-09-18 16:06:51 +0200713 rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200714 IPA_CMD_ASS_START, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100715 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100716 dev_warn(&card->gdev->dev,
717 "Starting ARP processing support for %s failed\n",
718 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100719 }
720 return rc;
721}
722
Frank Blaschka4a71df52008-02-15 09:19:42 +0100723static int qeth_l3_start_ipa_source_mac(struct qeth_card *card)
724{
725 int rc;
726
Carsten Otte847a50f2010-06-21 22:57:05 +0000727 QETH_CARD_TEXT(card, 3, "stsrcmac");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100728
Frank Blaschka4a71df52008-02-15 09:19:42 +0100729 if (!qeth_is_supported(card, IPA_SOURCE_MAC)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100730 dev_info(&card->gdev->dev,
Ursula Braunfe94e2e2009-01-04 17:34:52 -0800731 "Inbound source MAC-address not supported on %s\n",
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100732 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100733 return -EOPNOTSUPP;
734 }
735
Thomas Richter4d7def22015-09-18 16:06:51 +0200736 rc = qeth_send_simple_setassparms(card, IPA_SOURCE_MAC,
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200737 IPA_CMD_ASS_START, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100738 if (rc)
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100739 dev_warn(&card->gdev->dev,
Ursula Braunfe94e2e2009-01-04 17:34:52 -0800740 "Starting source MAC-address support for %s failed\n",
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100741 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100742 return rc;
743}
744
745static int qeth_l3_start_ipa_vlan(struct qeth_card *card)
746{
747 int rc = 0;
748
Carsten Otte847a50f2010-06-21 22:57:05 +0000749 QETH_CARD_TEXT(card, 3, "strtvlan");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100750
751 if (!qeth_is_supported(card, IPA_FULL_VLAN)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100752 dev_info(&card->gdev->dev,
753 "VLAN not supported on %s\n", QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100754 return -EOPNOTSUPP;
755 }
756
Thomas Richter4d7def22015-09-18 16:06:51 +0200757 rc = qeth_send_simple_setassparms(card, IPA_VLAN_PRIO,
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200758 IPA_CMD_ASS_START, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100759 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100760 dev_warn(&card->gdev->dev,
761 "Starting VLAN support for %s failed\n",
762 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100763 } else {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100764 dev_info(&card->gdev->dev, "VLAN enabled\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100765 }
766 return rc;
767}
768
769static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
770{
771 int rc;
772
Carsten Otte847a50f2010-06-21 22:57:05 +0000773 QETH_CARD_TEXT(card, 3, "stmcast");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100774
775 if (!qeth_is_supported(card, IPA_MULTICASTING)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100776 dev_info(&card->gdev->dev,
777 "Multicast not supported on %s\n",
778 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100779 return -EOPNOTSUPP;
780 }
781
Thomas Richter4d7def22015-09-18 16:06:51 +0200782 rc = qeth_send_simple_setassparms(card, IPA_MULTICASTING,
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200783 IPA_CMD_ASS_START, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100784 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100785 dev_warn(&card->gdev->dev,
786 "Starting multicast support for %s failed\n",
787 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100788 } else {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100789 dev_info(&card->gdev->dev, "Multicast enabled\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100790 card->dev->flags |= IFF_MULTICAST;
791 }
792 return rc;
793}
794
Frank Blaschka4a71df52008-02-15 09:19:42 +0100795static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
796{
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200797 u32 ipv6_data = 3;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100798 int rc;
799
Carsten Otte847a50f2010-06-21 22:57:05 +0000800 QETH_CARD_TEXT(card, 3, "softipv6");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100801
Julian Wiedmann379ac992019-04-25 18:25:57 +0200802 if (IS_IQD(card))
Julian Wiedmann23274592017-06-06 14:33:44 +0200803 goto out;
804
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200805 rc = qeth_send_simple_setassparms(card, IPA_IPV6, IPA_CMD_ASS_START,
806 &ipv6_data);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100807 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100808 dev_err(&card->gdev->dev,
809 "Activating IPv6 support for %s failed\n",
810 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100811 return rc;
812 }
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200813 rc = qeth_send_simple_setassparms_v6(card, IPA_IPV6, IPA_CMD_ASS_START,
814 NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100815 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100816 dev_err(&card->gdev->dev,
817 "Activating IPv6 support for %s failed\n",
818 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100819 return rc;
820 }
Kittipon Meesompopa8155b02018-04-26 09:42:21 +0200821 rc = qeth_send_simple_setassparms_v6(card, IPA_PASSTHRU,
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200822 IPA_CMD_ASS_START, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100823 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100824 dev_warn(&card->gdev->dev,
825 "Enabling the passthrough mode for %s failed\n",
826 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100827 return rc;
828 }
829out:
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100830 dev_info(&card->gdev->dev, "IPV6 enabled\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100831 return 0;
832}
Frank Blaschka4a71df52008-02-15 09:19:42 +0100833
834static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
835{
Carsten Otte847a50f2010-06-21 22:57:05 +0000836 QETH_CARD_TEXT(card, 3, "strtipv6");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100837
838 if (!qeth_is_supported(card, IPA_IPV6)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100839 dev_info(&card->gdev->dev,
840 "IPv6 not supported on %s\n", QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100841 return 0;
842 }
Julian Wiedmannc0622042017-12-20 20:10:58 +0100843 return qeth_l3_softsetup_ipv6(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100844}
845
846static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
847{
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200848 u32 filter_data = 1;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100849 int rc;
850
Carsten Otte847a50f2010-06-21 22:57:05 +0000851 QETH_CARD_TEXT(card, 3, "stbrdcst");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100852 card->info.broadcast_capable = 0;
853 if (!qeth_is_supported(card, IPA_FILTERING)) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100854 dev_info(&card->gdev->dev,
855 "Broadcast not supported on %s\n",
856 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100857 rc = -EOPNOTSUPP;
858 goto out;
859 }
Thomas Richter4d7def22015-09-18 16:06:51 +0200860 rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200861 IPA_CMD_ASS_START, NULL);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100862 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100863 dev_warn(&card->gdev->dev, "Enabling broadcast filtering for "
864 "%s failed\n", QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100865 goto out;
866 }
867
Thomas Richter4d7def22015-09-18 16:06:51 +0200868 rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200869 IPA_CMD_ASS_CONFIGURE, &filter_data);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100870 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100871 dev_warn(&card->gdev->dev,
872 "Setting up broadcast filtering for %s failed\n",
873 QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100874 goto out;
875 }
876 card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO;
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100877 dev_info(&card->gdev->dev, "Broadcast enabled\n");
Thomas Richter4d7def22015-09-18 16:06:51 +0200878 rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
Julian Wiedmann1c696c892019-06-27 17:01:23 +0200879 IPA_CMD_ASS_ENABLE, &filter_data);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100880 if (rc) {
Frank Blaschka74eacdb2008-12-25 13:39:49 +0100881 dev_warn(&card->gdev->dev, "Setting up broadcast echo "
882 "filtering for %s failed\n", QETH_CARD_IFNAME(card));
Frank Blaschka4a71df52008-02-15 09:19:42 +0100883 goto out;
884 }
885 card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO;
886out:
887 if (card->info.broadcast_capable)
888 card->dev->flags |= IFF_BROADCAST;
889 else
890 card->dev->flags &= ~IFF_BROADCAST;
891 return rc;
892}
893
Julian Wiedmann17d97232020-01-25 16:53:03 +0100894static void qeth_l3_start_ipassists(struct qeth_card *card)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100895{
Carsten Otte847a50f2010-06-21 22:57:05 +0000896 QETH_CARD_TEXT(card, 3, "strtipas");
Einar Lueckd64ecc22009-11-12 00:11:41 +0000897
Frank Blaschka4a71df52008-02-15 09:19:42 +0100898 qeth_l3_start_ipa_arp_processing(card); /* go on*/
Frank Blaschka4a71df52008-02-15 09:19:42 +0100899 qeth_l3_start_ipa_source_mac(card); /* go on*/
900 qeth_l3_start_ipa_vlan(card); /* go on*/
901 qeth_l3_start_ipa_multicast(card); /* go on*/
902 qeth_l3_start_ipa_ipv6(card); /* go on*/
903 qeth_l3_start_ipa_broadcast(card); /* go on*/
Frank Blaschka4a71df52008-02-15 09:19:42 +0100904}
905
Frank Blaschka4a71df52008-02-15 09:19:42 +0100906static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card,
907 struct qeth_reply *reply, unsigned long data)
908{
Julian Wiedmann742d4d42019-02-12 18:33:25 +0100909 struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100910
Julian Wiedmann742d4d42019-02-12 18:33:25 +0100911 if (cmd->hdr.return_code)
912 return -EIO;
Julian Wiedmann13bf82952020-02-27 18:08:11 +0100913 if (!is_valid_ether_addr(cmd->data.create_destroy_addr.mac_addr))
914 return -EADDRNOTAVAIL;
Julian Wiedmann742d4d42019-02-12 18:33:25 +0100915
916 ether_addr_copy(card->dev->dev_addr,
Julian Wiedmann9c6dc7a2020-02-27 18:08:10 +0100917 cmd->data.create_destroy_addr.mac_addr);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100918 return 0;
919}
920
921static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card)
922{
923 int rc = 0;
924 struct qeth_cmd_buffer *iob;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100925
Julian Wiedmann57a688aa2019-06-11 18:37:55 +0200926 QETH_CARD_TEXT(card, 2, "hsrmac");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100927
Julian Wiedmanna59d1212019-06-27 17:01:22 +0200928 iob = qeth_ipa_alloc_cmd(card, IPA_CMD_CREATE_ADDR, QETH_PROT_IPV6,
929 IPA_DATA_SIZEOF(create_destroy_addr));
Thomas Richter1aec42b2015-01-21 13:39:10 +0100930 if (!iob)
931 return -ENOMEM;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100932
933 rc = qeth_send_ipa_cmd(card, iob, qeth_l3_iqd_read_initial_mac_cb,
934 NULL);
935 return rc;
936}
937
938static int qeth_l3_get_unique_id_cb(struct qeth_card *card,
939 struct qeth_reply *reply, unsigned long data)
940{
Julian Wiedmann742d4d42019-02-12 18:33:25 +0100941 struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
Julian Wiedmann8ec1e242020-03-25 10:35:01 +0100942 u16 *uid = reply->param;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100943
Julian Wiedmann742d4d42019-02-12 18:33:25 +0100944 if (cmd->hdr.return_code == 0) {
Julian Wiedmann8ec1e242020-03-25 10:35:01 +0100945 *uid = cmd->data.create_destroy_addr.uid;
Julian Wiedmann742d4d42019-02-12 18:33:25 +0100946 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100947 }
Julian Wiedmann742d4d42019-02-12 18:33:25 +0100948
Julian Wiedmann742d4d42019-02-12 18:33:25 +0100949 dev_warn(&card->gdev->dev, "The network adapter failed to generate a unique ID\n");
950 return -EIO;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100951}
952
Julian Wiedmann8ec1e242020-03-25 10:35:01 +0100953static u16 qeth_l3_get_unique_id(struct qeth_card *card, u16 uid)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100954{
Frank Blaschka4a71df52008-02-15 09:19:42 +0100955 struct qeth_cmd_buffer *iob;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100956
Julian Wiedmann57a688aa2019-06-11 18:37:55 +0200957 QETH_CARD_TEXT(card, 2, "guniqeid");
Frank Blaschka4a71df52008-02-15 09:19:42 +0100958
Julian Wiedmann8ec1e242020-03-25 10:35:01 +0100959 if (!qeth_is_supported(card, IPA_IPV6))
960 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100961
Julian Wiedmanna59d1212019-06-27 17:01:22 +0200962 iob = qeth_ipa_alloc_cmd(card, IPA_CMD_CREATE_ADDR, QETH_PROT_IPV6,
963 IPA_DATA_SIZEOF(create_destroy_addr));
Thomas Richter1aec42b2015-01-21 13:39:10 +0100964 if (!iob)
Julian Wiedmann8ec1e242020-03-25 10:35:01 +0100965 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100966
Julian Wiedmann8ec1e242020-03-25 10:35:01 +0100967 __ipa_cmd(iob)->data.create_destroy_addr.uid = uid;
968 qeth_send_ipa_cmd(card, iob, qeth_l3_get_unique_id_cb, &uid);
969
970out:
971 return uid;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100972}
973
Ursula Braun76b11f82010-01-11 02:50:50 +0000974static int
975qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
976 unsigned long data)
977{
978 struct qeth_ipa_cmd *cmd;
979 __u16 rc;
980
Julian Wiedmann57a688aa2019-06-11 18:37:55 +0200981 QETH_CARD_TEXT(card, 2, "diastrcb");
Ursula Braun76b11f82010-01-11 02:50:50 +0000982
983 cmd = (struct qeth_ipa_cmd *)data;
984 rc = cmd->hdr.return_code;
Ursula Brauna9591892010-03-08 20:36:55 +0000985 if (rc)
Carsten Otte847a50f2010-06-21 22:57:05 +0000986 QETH_CARD_TEXT_(card, 2, "dxter%x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +0000987 switch (cmd->data.diagass.action) {
988 case QETH_DIAGS_CMD_TRACE_QUERY:
989 break;
990 case QETH_DIAGS_CMD_TRACE_DISABLE:
Ursula Brauna9591892010-03-08 20:36:55 +0000991 switch (rc) {
992 case 0:
993 case IPA_RC_INVALID_SUBCMD:
994 card->info.promisc_mode = SET_PROMISC_MODE_OFF;
995 dev_info(&card->gdev->dev, "The HiperSockets network "
996 "traffic analyzer is deactivated\n");
997 break;
998 default:
999 break;
1000 }
Ursula Braun76b11f82010-01-11 02:50:50 +00001001 break;
1002 case QETH_DIAGS_CMD_TRACE_ENABLE:
Ursula Brauna9591892010-03-08 20:36:55 +00001003 switch (rc) {
1004 case 0:
1005 card->info.promisc_mode = SET_PROMISC_MODE_ON;
1006 dev_info(&card->gdev->dev, "The HiperSockets network "
1007 "traffic analyzer is activated\n");
1008 break;
1009 case IPA_RC_HARDWARE_AUTH_ERROR:
1010 dev_warn(&card->gdev->dev, "The device is not "
1011 "authorized to run as a HiperSockets network "
1012 "traffic analyzer\n");
1013 break;
1014 case IPA_RC_TRACE_ALREADY_ACTIVE:
1015 dev_warn(&card->gdev->dev, "A HiperSockets "
1016 "network traffic analyzer is already "
1017 "active in the HiperSockets LAN\n");
1018 break;
1019 default:
1020 break;
1021 }
Ursula Braun76b11f82010-01-11 02:50:50 +00001022 break;
1023 default:
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001024 QETH_DBF_MESSAGE(2, "Unknown sniffer action (%#06x) on device %x\n",
1025 cmd->data.diagass.action, CARD_DEVID(card));
Ursula Braun76b11f82010-01-11 02:50:50 +00001026 }
1027
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001028 return rc ? -EIO : 0;
Ursula Braun76b11f82010-01-11 02:50:50 +00001029}
1030
1031static int
1032qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
1033{
1034 struct qeth_cmd_buffer *iob;
1035 struct qeth_ipa_cmd *cmd;
1036
Julian Wiedmann57a688aa2019-06-11 18:37:55 +02001037 QETH_CARD_TEXT(card, 2, "diagtrac");
Ursula Braun76b11f82010-01-11 02:50:50 +00001038
Julian Wiedmann5cfbe102019-06-27 17:01:25 +02001039 iob = qeth_get_diag_cmd(card, QETH_DIAGS_CMD_TRACE, 0);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001040 if (!iob)
1041 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +01001042 cmd = __ipa_cmd(iob);
Ursula Braun76b11f82010-01-11 02:50:50 +00001043 cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET;
1044 cmd->data.diagass.action = diags_cmd;
1045 return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
1046}
1047
Julian Wiedmann8659c182019-11-14 11:19:22 +01001048static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg)
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001049{
Julian Wiedmann8659c182019-11-14 11:19:22 +01001050 struct qeth_card *card = arg;
Julian Wiedmann611abe52019-11-14 11:19:21 +01001051 struct inet6_dev *in6_dev;
1052 struct in_device *in4_dev;
1053 struct qeth_ipaddr *ipm;
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001054 struct qeth_ipaddr tmp;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001055 struct ip_mc_list *im4;
Julian Wiedmann611abe52019-11-14 11:19:21 +01001056 struct ifmcaddr6 *im6;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001057
Carsten Otte847a50f2010-06-21 22:57:05 +00001058 QETH_CARD_TEXT(card, 4, "addmc");
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001059
Julian Wiedmann611abe52019-11-14 11:19:21 +01001060 if (!dev || !(dev->flags & IFF_UP))
1061 goto out;
1062
Julian Wiedmann8659c182019-11-14 11:19:22 +01001063 in4_dev = __in_dev_get_rtnl(dev);
Julian Wiedmann611abe52019-11-14 11:19:21 +01001064 if (!in4_dev)
1065 goto walk_ipv6;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001066
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001067 qeth_l3_init_ipaddr(&tmp, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV4);
1068 tmp.disp_flag = QETH_DISP_ADDR_ADD;
1069 tmp.is_multicast = 1;
1070
Julian Wiedmann8659c182019-11-14 11:19:22 +01001071 for (im4 = rtnl_dereference(in4_dev->mc_list); im4 != NULL;
1072 im4 = rtnl_dereference(im4->next_rcu)) {
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001073 tmp.u.a4.addr = im4->multiaddr;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001074
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001075 ipm = qeth_l3_find_addr_by_ip(card, &tmp);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001076 if (ipm) {
Julian Wiedmannc5c48c52018-02-27 18:58:16 +01001077 /* for mcast, by-IP match means full match */
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001078 ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001079 continue;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001080 }
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001081
1082 ipm = kmemdup(&tmp, sizeof(tmp), GFP_KERNEL);
1083 if (!ipm)
1084 continue;
1085
Julian Wiedmann09732922020-07-14 16:23:04 +02001086 hash_add(card->rx_mode_addrs, &ipm->hnode,
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001087 qeth_l3_ipaddr_hash(ipm));
Frank Blaschka4a71df52008-02-15 09:19:42 +01001088 }
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001089
Julian Wiedmann611abe52019-11-14 11:19:21 +01001090walk_ipv6:
1091 if (!qeth_is_supported(card, IPA_IPV6))
1092 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001093
Julian Wiedmann611abe52019-11-14 11:19:21 +01001094 in6_dev = __in6_dev_get(dev);
1095 if (!in6_dev)
1096 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001097
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001098 qeth_l3_init_ipaddr(&tmp, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6);
1099 tmp.disp_flag = QETH_DISP_ADDR_ADD;
1100 tmp.is_multicast = 1;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001101
Julian Wiedmannddf28102019-11-14 11:19:19 +01001102 read_lock_bh(&in6_dev->lock);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001103 for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001104 tmp.u.a6.addr = im6->mca_addr;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001105
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001106 ipm = qeth_l3_find_addr_by_ip(card, &tmp);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001107 if (ipm) {
Julian Wiedmannc5c48c52018-02-27 18:58:16 +01001108 /* for mcast, by-IP match means full match */
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001109 ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
1110 continue;
1111 }
1112
Julian Wiedmannb80c08a2019-11-14 11:19:23 +01001113 ipm = kmemdup(&tmp, sizeof(tmp), GFP_ATOMIC);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001114 if (!ipm)
1115 continue;
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001116
Julian Wiedmann09732922020-07-14 16:23:04 +02001117 hash_add(card->rx_mode_addrs, &ipm->hnode,
1118 qeth_l3_ipaddr_hash(ipm));
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001119
Frank Blaschka4a71df52008-02-15 09:19:42 +01001120 }
Julian Wiedmannddf28102019-11-14 11:19:19 +01001121 read_unlock_bh(&in6_dev->lock);
1122
Julian Wiedmann611abe52019-11-14 11:19:21 +01001123out:
Julian Wiedmann8659c182019-11-14 11:19:22 +01001124 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001125}
1126
Patrick McHardy80d5c362013-04-19 02:04:28 +00001127static int qeth_l3_vlan_rx_add_vid(struct net_device *dev,
1128 __be16 proto, u16 vid)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001129{
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001130 struct qeth_card *card = dev->ml_priv;
1131
Julian Wiedmann8659c182019-11-14 11:19:22 +01001132 QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
Jiri Pirko8e586132011-12-08 19:52:37 -05001133 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001134}
1135
Patrick McHardy80d5c362013-04-19 02:04:28 +00001136static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
1137 __be16 proto, u16 vid)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001138{
Heiko Carstens509e2562008-07-26 02:24:10 -07001139 struct qeth_card *card = dev->ml_priv;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001140
Carsten Otte847a50f2010-06-21 22:57:05 +00001141 QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
Jiri Pirko8e586132011-12-08 19:52:37 -05001142 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001143}
1144
Julian Wiedmann59b757a2019-08-20 16:46:41 +02001145static void qeth_l3_set_promisc_mode(struct qeth_card *card)
Ursula Braun76b11f82010-01-11 02:50:50 +00001146{
Julian Wiedmann59b757a2019-08-20 16:46:41 +02001147 bool enable = card->dev->flags & IFF_PROMISC;
Ursula Braun76b11f82010-01-11 02:50:50 +00001148
Julian Wiedmann59b757a2019-08-20 16:46:41 +02001149 if (card->info.promisc_mode == enable)
Ursula Braun76b11f82010-01-11 02:50:50 +00001150 return;
1151
Julian Wiedmann379ac992019-04-25 18:25:57 +02001152 if (IS_VM_NIC(card)) { /* Guestlan trace */
Ursula Braun76b11f82010-01-11 02:50:50 +00001153 if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
Julian Wiedmann59b757a2019-08-20 16:46:41 +02001154 qeth_setadp_promisc_mode(card, enable);
Ursula Braun76b11f82010-01-11 02:50:50 +00001155 } else if (card->options.sniffer && /* HiperSockets trace */
1156 qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
Julian Wiedmann59b757a2019-08-20 16:46:41 +02001157 if (enable) {
Carsten Otte847a50f2010-06-21 22:57:05 +00001158 QETH_CARD_TEXT(card, 3, "+promisc");
Ursula Braun76b11f82010-01-11 02:50:50 +00001159 qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE);
1160 } else {
Carsten Otte847a50f2010-06-21 22:57:05 +00001161 QETH_CARD_TEXT(card, 3, "-promisc");
Ursula Braun76b11f82010-01-11 02:50:50 +00001162 qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
1163 }
1164 }
1165}
1166
Julian Wiedmannd0c74822019-03-28 16:39:19 +01001167static void qeth_l3_rx_mode_work(struct work_struct *work)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001168{
Julian Wiedmannd0c74822019-03-28 16:39:19 +01001169 struct qeth_card *card = container_of(work, struct qeth_card,
1170 rx_mode_work);
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001171 struct qeth_ipaddr *addr;
1172 struct hlist_node *tmp;
1173 int i, rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001174
Carsten Otte847a50f2010-06-21 22:57:05 +00001175 QETH_CARD_TEXT(card, 3, "setmulti");
Julian Wiedmanne6e771b2019-01-25 15:44:22 +01001176
Ursula Braun76b11f82010-01-11 02:50:50 +00001177 if (!card->options.sniffer) {
Julian Wiedmann8659c182019-11-14 11:19:22 +01001178 rtnl_lock();
1179 qeth_l3_add_mcast_rtnl(card->dev, 0, card);
Julian Wiedmann611abe52019-11-14 11:19:21 +01001180 if (qeth_is_supported(card, IPA_FULL_VLAN))
Julian Wiedmann8659c182019-11-14 11:19:22 +01001181 vlan_for_each(card->dev, qeth_l3_add_mcast_rtnl, card);
1182 rtnl_unlock();
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001183
Julian Wiedmann09732922020-07-14 16:23:04 +02001184 hash_for_each_safe(card->rx_mode_addrs, i, tmp, addr, hnode) {
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001185 switch (addr->disp_flag) {
1186 case QETH_DISP_ADDR_DELETE:
1187 rc = qeth_l3_deregister_addr_entry(card, addr);
Julian Wiedmann4b7ae122019-02-12 18:33:23 +01001188 if (!rc || rc == -ENOENT) {
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001189 hash_del(&addr->hnode);
1190 kfree(addr);
1191 }
1192 break;
1193 case QETH_DISP_ADDR_ADD:
1194 rc = qeth_l3_register_addr_entry(card, addr);
Julian Wiedmann4b7ae122019-02-12 18:33:23 +01001195 if (rc && rc != -ENETDOWN) {
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001196 hash_del(&addr->hnode);
1197 kfree(addr);
1198 break;
1199 }
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05001200 fallthrough;
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001201 default:
1202 /* for next call to set_rx_mode(): */
1203 addr->disp_flag = QETH_DISP_ADDR_DELETE;
1204 }
1205 }
Ursula Braun76b11f82010-01-11 02:50:50 +00001206 }
Julian Wiedmann59b757a2019-08-20 16:46:41 +02001207
1208 qeth_l3_set_promisc_mode(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001209}
1210
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001211static int qeth_l3_arp_makerc(u16 rc)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001212{
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001213 switch (rc) {
1214 case IPA_RC_SUCCESS:
1215 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001216 case QETH_IPA_ARP_RC_NOTSUPP:
Frank Blaschka4a71df52008-02-15 09:19:42 +01001217 case QETH_IPA_ARP_RC_Q_NOTSUPP:
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001218 return -EOPNOTSUPP;
1219 case QETH_IPA_ARP_RC_OUT_OF_RANGE:
1220 return -EINVAL;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001221 case QETH_IPA_ARP_RC_Q_NO_DATA:
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001222 return -ENOENT;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001223 default:
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001224 return -EIO;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001225 }
1226}
1227
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001228static int qeth_l3_arp_cmd_cb(struct qeth_card *card, struct qeth_reply *reply,
1229 unsigned long data)
1230{
1231 struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
1232
1233 qeth_setassparms_cb(card, reply, data);
1234 return qeth_l3_arp_makerc(cmd->hdr.return_code);
1235}
1236
Frank Blaschka4a71df52008-02-15 09:19:42 +01001237static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
1238{
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001239 struct qeth_cmd_buffer *iob;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001240 int rc;
1241
Carsten Otte847a50f2010-06-21 22:57:05 +00001242 QETH_CARD_TEXT(card, 3, "arpstnoe");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001243
1244 /*
1245 * currently GuestLAN only supports the ARP assist function
1246 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_SET_NO_ENTRIES;
1247 * thus we say EOPNOTSUPP for this ARP function
1248 */
Julian Wiedmann379ac992019-04-25 18:25:57 +02001249 if (IS_VM_NIC(card))
Frank Blaschka4a71df52008-02-15 09:19:42 +01001250 return -EOPNOTSUPP;
1251 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001252 return -EOPNOTSUPP;
1253 }
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001254
1255 iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
Julian Wiedmannb9150462019-06-27 17:01:24 +02001256 IPA_CMD_ASS_ARP_SET_NO_ENTRIES,
1257 SETASS_DATA_SIZEOF(flags_32bit),
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001258 QETH_PROT_IPV4);
1259 if (!iob)
1260 return -ENOMEM;
1261
1262 __ipa_cmd(iob)->data.setassparms.data.flags_32bit = (u32) no_entries;
1263 rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001264 if (rc)
1265 QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on device %x: %#x\n",
1266 CARD_DEVID(card), rc);
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001267 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001268}
1269
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001270static __u32 get_arp_entry_size(struct qeth_card *card,
1271 struct qeth_arp_query_data *qdata,
1272 struct qeth_arp_entrytype *type, __u8 strip_entries)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001273{
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001274 __u32 rc;
1275 __u8 is_hsi;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001276
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001277 is_hsi = qdata->reply_bits == 5;
1278 if (type->ip == QETHARP_IP_ADDR_V4) {
1279 QETH_CARD_TEXT(card, 4, "arpev4");
1280 if (strip_entries) {
1281 rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5_short) :
1282 sizeof(struct qeth_arp_qi_entry7_short);
1283 } else {
1284 rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5) :
1285 sizeof(struct qeth_arp_qi_entry7);
1286 }
1287 } else if (type->ip == QETHARP_IP_ADDR_V6) {
1288 QETH_CARD_TEXT(card, 4, "arpev6");
1289 if (strip_entries) {
1290 rc = is_hsi ?
1291 sizeof(struct qeth_arp_qi_entry5_short_ipv6) :
1292 sizeof(struct qeth_arp_qi_entry7_short_ipv6);
1293 } else {
1294 rc = is_hsi ?
1295 sizeof(struct qeth_arp_qi_entry5_ipv6) :
1296 sizeof(struct qeth_arp_qi_entry7_ipv6);
1297 }
1298 } else {
1299 QETH_CARD_TEXT(card, 4, "arpinv");
1300 rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001301 }
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001302
1303 return rc;
1304}
1305
1306static int arpentry_matches_prot(struct qeth_arp_entrytype *type, __u16 prot)
1307{
1308 return (type->ip == QETHARP_IP_ADDR_V4 && prot == QETH_PROT_IPV4) ||
1309 (type->ip == QETHARP_IP_ADDR_V6 && prot == QETH_PROT_IPV6);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001310}
1311
1312static int qeth_l3_arp_query_cb(struct qeth_card *card,
1313 struct qeth_reply *reply, unsigned long data)
1314{
1315 struct qeth_ipa_cmd *cmd;
1316 struct qeth_arp_query_data *qdata;
1317 struct qeth_arp_query_info *qinfo;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001318 int e;
1319 int entrybytes_done;
1320 int stripped_bytes;
1321 __u8 do_strip_entries;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001322
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001323 QETH_CARD_TEXT(card, 3, "arpquecb");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001324
1325 qinfo = (struct qeth_arp_query_info *) reply->param;
1326 cmd = (struct qeth_ipa_cmd *) data;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001327 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.prot_version);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001328 if (cmd->hdr.return_code) {
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001329 QETH_CARD_TEXT(card, 4, "arpcberr");
1330 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
Julian Wiedmann4b7ae122019-02-12 18:33:23 +01001331 return qeth_l3_arp_makerc(cmd->hdr.return_code);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001332 }
1333 if (cmd->data.setassparms.hdr.return_code) {
1334 cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001335 QETH_CARD_TEXT(card, 4, "setaperr");
1336 QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
Julian Wiedmann4b7ae122019-02-12 18:33:23 +01001337 return qeth_l3_arp_makerc(cmd->hdr.return_code);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001338 }
1339 qdata = &cmd->data.setassparms.data.query_arp;
Carsten Otte847a50f2010-06-21 22:57:05 +00001340 QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001341
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001342 do_strip_entries = (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) > 0;
1343 stripped_bytes = do_strip_entries ? QETH_QARP_MEDIASPECIFIC_BYTES : 0;
1344 entrybytes_done = 0;
1345 for (e = 0; e < qdata->no_entries; ++e) {
1346 char *cur_entry;
1347 __u32 esize;
1348 struct qeth_arp_entrytype *etype;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001349
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001350 cur_entry = &qdata->data + entrybytes_done;
1351 etype = &((struct qeth_arp_qi_entry5 *) cur_entry)->type;
1352 if (!arpentry_matches_prot(etype, cmd->hdr.prot_version)) {
1353 QETH_CARD_TEXT(card, 4, "pmis");
1354 QETH_CARD_TEXT_(card, 4, "%i", etype->ip);
1355 break;
1356 }
1357 esize = get_arp_entry_size(card, qdata, etype,
1358 do_strip_entries);
1359 QETH_CARD_TEXT_(card, 5, "esz%i", esize);
1360 if (!esize)
1361 break;
1362
1363 if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
Julian Wiedmann4b7ae122019-02-12 18:33:23 +01001364 QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOSPC);
1365 memset(qinfo->udata, 0, 4);
1366 return -ENOSPC;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001367 }
1368
1369 memcpy(qinfo->udata + qinfo->udata_offset,
1370 &qdata->data + entrybytes_done + stripped_bytes,
1371 esize);
1372 entrybytes_done += esize + stripped_bytes;
1373 qinfo->udata_offset += esize;
1374 ++qinfo->no_entries;
1375 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001376 /* check if all replies received ... */
1377 if (cmd->data.setassparms.hdr.seq_no <
1378 cmd->data.setassparms.hdr.number_of_replies)
1379 return 1;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001380 QETH_CARD_TEXT_(card, 4, "nove%i", qinfo->no_entries);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001381 memcpy(qinfo->udata, &qinfo->no_entries, 4);
1382 /* keep STRIP_ENTRIES flag so the user program can distinguish
1383 * stripped entries from normal ones */
1384 if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
1385 qdata->reply_bits |= QETH_QARP_STRIP_ENTRIES;
1386 memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001387 QETH_CARD_TEXT_(card, 4, "rc%i", 0);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001388 return 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001389}
1390
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001391static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
1392 enum qeth_prot_versions prot,
1393 struct qeth_arp_query_info *qinfo)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001394{
1395 struct qeth_cmd_buffer *iob;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001396 struct qeth_ipa_cmd *cmd;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001397 int rc;
1398
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001399 QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot);
1400
Thomas Richterb475e312015-12-11 12:27:54 +01001401 iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
1402 IPA_CMD_ASS_ARP_QUERY_INFO,
Julian Wiedmannb9150462019-06-27 17:01:24 +02001403 SETASS_DATA_SIZEOF(query_arp), prot);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001404 if (!iob)
1405 return -ENOMEM;
Julian Wiedmannff5caa72018-03-09 18:12:52 +01001406 cmd = __ipa_cmd(iob);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001407 cmd->data.setassparms.data.query_arp.request_bits = 0x000F;
Julian Wiedmann84dbea42019-02-12 18:33:16 +01001408 rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_query_cb, qinfo);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001409 if (rc)
1410 QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n",
1411 CARD_DEVID(card), rc);
Julian Wiedmann4b7ae122019-02-12 18:33:23 +01001412 return rc;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001413}
1414
1415static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
1416{
1417 struct qeth_arp_query_info qinfo = {0, };
1418 int rc;
1419
Carsten Otte847a50f2010-06-21 22:57:05 +00001420 QETH_CARD_TEXT(card, 3, "arpquery");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001421
1422 if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/
1423 IPA_ARP_PROCESSING)) {
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001424 QETH_CARD_TEXT(card, 3, "arpqnsup");
1425 rc = -EOPNOTSUPP;
1426 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001427 }
1428 /* get size of userspace buffer and mask_bits -> 6 bytes */
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001429 if (copy_from_user(&qinfo, udata, 6)) {
1430 rc = -EFAULT;
1431 goto out;
1432 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001433 qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001434 if (!qinfo.udata) {
1435 rc = -ENOMEM;
1436 goto out;
1437 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001438 qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET;
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001439 rc = qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV4, &qinfo);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001440 if (rc) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001441 if (copy_to_user(udata, qinfo.udata, 4))
1442 rc = -EFAULT;
Sebastian Ott77a83ed2016-06-16 16:19:03 +02001443 goto free_and_out;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001444 }
Sebastian Ott77a83ed2016-06-16 16:19:03 +02001445 if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) {
1446 /* fails in case of GuestLAN QDIO mode */
1447 qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6, &qinfo);
1448 }
Sebastian Ott77a83ed2016-06-16 16:19:03 +02001449 if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) {
1450 QETH_CARD_TEXT(card, 4, "qactf");
1451 rc = -EFAULT;
1452 goto free_and_out;
1453 }
1454 QETH_CARD_TEXT(card, 4, "qacts");
1455
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001456free_and_out:
Frank Blaschka4a71df52008-02-15 09:19:42 +01001457 kfree(qinfo.udata);
Einar Lueckd0ddf30f2010-12-08 02:57:58 +00001458out:
Frank Blaschka4a71df52008-02-15 09:19:42 +01001459 return rc;
1460}
1461
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001462static int qeth_l3_arp_modify_entry(struct qeth_card *card,
1463 struct qeth_arp_cache_entry *entry,
1464 enum qeth_arp_process_subcmds arp_cmd)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001465{
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001466 struct qeth_arp_cache_entry *cmd_entry;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001467 struct qeth_cmd_buffer *iob;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001468 int rc;
1469
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001470 if (arp_cmd == IPA_CMD_ASS_ARP_ADD_ENTRY)
1471 QETH_CARD_TEXT(card, 3, "arpadd");
1472 else
1473 QETH_CARD_TEXT(card, 3, "arpdel");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001474
1475 /*
1476 * currently GuestLAN only supports the ARP assist function
1477 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_ADD_ENTRY;
1478 * thus we say EOPNOTSUPP for this ARP function
1479 */
Julian Wiedmann379ac992019-04-25 18:25:57 +02001480 if (IS_VM_NIC(card))
Frank Blaschka4a71df52008-02-15 09:19:42 +01001481 return -EOPNOTSUPP;
1482 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001483 return -EOPNOTSUPP;
1484 }
1485
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001486 iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING, arp_cmd,
Julian Wiedmannb9150462019-06-27 17:01:24 +02001487 SETASS_DATA_SIZEOF(arp_entry),
1488 QETH_PROT_IPV4);
Thomas Richter1aec42b2015-01-21 13:39:10 +01001489 if (!iob)
1490 return -ENOMEM;
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001491
1492 cmd_entry = &__ipa_cmd(iob)->data.setassparms.data.arp_entry;
1493 ether_addr_copy(cmd_entry->macaddr, entry->macaddr);
1494 memcpy(cmd_entry->ipaddr, entry->ipaddr, 4);
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001495 rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001496 if (rc)
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001497 QETH_DBF_MESSAGE(2, "Could not modify (cmd: %#x) ARP entry on device %x: %#x\n",
1498 arp_cmd, CARD_DEVID(card), rc);
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001499 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001500}
1501
1502static int qeth_l3_arp_flush_cache(struct qeth_card *card)
1503{
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001504 struct qeth_cmd_buffer *iob;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001505 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001506
Carsten Otte847a50f2010-06-21 22:57:05 +00001507 QETH_CARD_TEXT(card, 3, "arpflush");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001508
1509 /*
1510 * currently GuestLAN only supports the ARP assist function
1511 * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_FLUSH_CACHE;
1512 * thus we say EOPNOTSUPP for this ARP function
1513 */
Julian Wiedmann379ac992019-04-25 18:25:57 +02001514 if (IS_VM_NIC(card) || IS_IQD(card))
Frank Blaschka4a71df52008-02-15 09:19:42 +01001515 return -EOPNOTSUPP;
1516 if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001517 return -EOPNOTSUPP;
1518 }
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001519
1520 iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
1521 IPA_CMD_ASS_ARP_FLUSH_CACHE, 0,
1522 QETH_PROT_IPV4);
1523 if (!iob)
1524 return -ENOMEM;
1525
1526 rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
Julian Wiedmanne19e5be2018-11-02 19:04:08 +01001527 if (rc)
1528 QETH_DBF_MESSAGE(2, "Could not flush ARP cache on device %x: %#x\n",
1529 CARD_DEVID(card), rc);
Julian Wiedmann742d4d42019-02-12 18:33:25 +01001530 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001531}
1532
1533static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
1534{
Heiko Carstens509e2562008-07-26 02:24:10 -07001535 struct qeth_card *card = dev->ml_priv;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001536 struct qeth_arp_cache_entry arp_entry;
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001537 enum qeth_arp_process_subcmds arp_cmd;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001538 int rc = 0;
1539
Frank Blaschka4a71df52008-02-15 09:19:42 +01001540 switch (cmd) {
1541 case SIOC_QETH_ARP_SET_NO_ENTRIES:
1542 if (!capable(CAP_NET_ADMIN)) {
1543 rc = -EPERM;
1544 break;
1545 }
1546 rc = qeth_l3_arp_set_no_entries(card, rq->ifr_ifru.ifru_ivalue);
1547 break;
1548 case SIOC_QETH_ARP_QUERY_INFO:
1549 if (!capable(CAP_NET_ADMIN)) {
1550 rc = -EPERM;
1551 break;
1552 }
1553 rc = qeth_l3_arp_query(card, rq->ifr_ifru.ifru_data);
1554 break;
1555 case SIOC_QETH_ARP_ADD_ENTRY:
Frank Blaschka4a71df52008-02-15 09:19:42 +01001556 case SIOC_QETH_ARP_REMOVE_ENTRY:
Julian Wiedmann125d7d32018-11-02 19:04:12 +01001557 if (!capable(CAP_NET_ADMIN))
1558 return -EPERM;
1559 if (copy_from_user(&arp_entry, rq->ifr_data, sizeof(arp_entry)))
1560 return -EFAULT;
1561
1562 arp_cmd = (cmd == SIOC_QETH_ARP_ADD_ENTRY) ?
1563 IPA_CMD_ASS_ARP_ADD_ENTRY :
1564 IPA_CMD_ASS_ARP_REMOVE_ENTRY;
1565 return qeth_l3_arp_modify_entry(card, &arp_entry, arp_cmd);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001566 case SIOC_QETH_ARP_FLUSH_CACHE:
1567 if (!capable(CAP_NET_ADMIN)) {
1568 rc = -EPERM;
1569 break;
1570 }
1571 rc = qeth_l3_arp_flush_cache(card);
1572 break;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001573 default:
1574 rc = -EOPNOTSUPP;
1575 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01001576 return rc;
1577}
1578
Julian Wiedmann980f4562019-06-27 17:01:32 +02001579static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst,
1580 int ipv)
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001581{
David S. Miller69cce1d2011-07-17 23:09:49 -07001582 struct neighbour *n = NULL;
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001583
Julian Wiedmann980f4562019-06-27 17:01:32 +02001584 if (dst)
1585 n = dst_neigh_lookup_skb(dst, skb);
Julian Wiedmann0cd6783d32019-06-05 13:48:49 +02001586
David S. Miller69cce1d2011-07-17 23:09:49 -07001587 if (n) {
Julian Wiedmann1f979122017-12-20 20:11:04 +01001588 int cast_type = n->type;
1589
David S. Miller24db1ba2012-07-02 22:02:33 -07001590 neigh_release(n);
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001591 if ((cast_type == RTN_BROADCAST) ||
1592 (cast_type == RTN_MULTICAST) ||
1593 (cast_type == RTN_ANYCAST))
1594 return cast_type;
Julian Wiedmann86c0cdb2018-07-11 17:42:41 +02001595 return RTN_UNICAST;
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001596 }
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001597
Julian Wiedmann1f979122017-12-20 20:11:04 +01001598 /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
Julian Wiedmann0cd6783d32019-06-05 13:48:49 +02001599 switch (ipv) {
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001600 case 4:
Julian Wiedmann72c87972019-06-05 13:48:48 +02001601 if (ipv4_is_lbcast(ip_hdr(skb)->daddr))
1602 return RTN_BROADCAST;
Julian Wiedmann1f979122017-12-20 20:11:04 +01001603 return ipv4_is_multicast(ip_hdr(skb)->daddr) ?
Julian Wiedmann86c0cdb2018-07-11 17:42:41 +02001604 RTN_MULTICAST : RTN_UNICAST;
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001605 case 6:
1606 return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
1607 RTN_MULTICAST : RTN_UNICAST;
1608 default:
1609 /* ... and MAC address */
Julian Wiedmann58aa2492019-04-25 18:26:00 +02001610 return qeth_get_ether_cast_type(skb);
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001611 }
Klaus-Dieter Wackerce73e102009-08-26 02:01:08 +00001612}
1613
Julian Wiedmann980f4562019-06-27 17:01:32 +02001614static int qeth_l3_get_cast_type(struct sk_buff *skb)
1615{
1616 int ipv = qeth_get_ip_version(skb);
1617 struct dst_entry *dst;
1618 int cast_type;
1619
1620 rcu_read_lock();
1621 dst = qeth_dst_check_rcu(skb, ipv);
1622 cast_type = qeth_l3_get_cast_type_rcu(skb, dst, ipv);
1623 rcu_read_unlock();
1624
1625 return cast_type;
1626}
1627
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001628static u8 qeth_l3_cast_type_to_flag(int cast_type)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001629{
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001630 if (cast_type == RTN_MULTICAST)
1631 return QETH_CAST_MULTICAST;
1632 if (cast_type == RTN_ANYCAST)
1633 return QETH_CAST_ANYCAST;
1634 if (cast_type == RTN_BROADCAST)
1635 return QETH_CAST_BROADCAST;
1636 return QETH_CAST_UNICAST;
1637}
David S. Miller69cce1d2011-07-17 23:09:49 -07001638
Julian Wiedmannb0abc4f2019-02-15 19:22:29 +01001639static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
1640 struct qeth_hdr *hdr, struct sk_buff *skb,
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001641 int ipv, unsigned int data_len)
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001642{
Julian Wiedmann5a541f62018-11-08 15:06:16 +01001643 struct qeth_hdr_layer3 *l3_hdr = &hdr->hdr.l3;
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001644 struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
Julian Wiedmannb0abc4f2019-02-15 19:22:29 +01001645 struct qeth_card *card = queue->card;
Julian Wiedmann0cd6783d32019-06-05 13:48:49 +02001646 struct dst_entry *dst;
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001647 int cast_type;
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001648
Julian Wiedmannf6c13142017-12-20 20:11:08 +01001649 hdr->hdr.l3.length = data_len;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001650
Julian Wiedmanne517b642018-09-17 17:36:02 +02001651 if (skb_is_gso(skb)) {
Julian Wiedmann0aef8392018-10-12 17:27:15 +02001652 hdr->hdr.l3.id = QETH_HEADER_TYPE_L3_TSO;
Julian Wiedmanne517b642018-09-17 17:36:02 +02001653 } else {
1654 hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
Julian Wiedmann5a541f62018-11-08 15:06:16 +01001655
1656 if (skb->protocol == htons(ETH_P_AF_IUCV)) {
1657 l3_hdr->flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
Julian Wiedmann1d38c2e2020-05-06 10:09:43 +02001658 l3_hdr->next_hop.addr.s6_addr16[0] = htons(0xfe80);
1659 memcpy(&l3_hdr->next_hop.addr.s6_addr32[2],
Julian Wiedmann5a541f62018-11-08 15:06:16 +01001660 iucv_trans_hdr(skb)->destUserID, 8);
1661 return;
1662 }
1663
Julian Wiedmanne517b642018-09-17 17:36:02 +02001664 if (skb->ip_summed == CHECKSUM_PARTIAL) {
1665 qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv);
1666 /* some HW requires combined L3+L4 csum offload: */
1667 if (ipv == 4)
1668 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ;
Julian Wiedmanne517b642018-09-17 17:36:02 +02001669 }
1670 }
1671
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001672 if (ipv == 4 || IS_IQD(card)) {
1673 /* NETIF_F_HW_VLAN_CTAG_TX */
1674 if (skb_vlan_tag_present(skb)) {
1675 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_VLAN_FRAME;
1676 hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
1677 }
1678 } else if (veth->h_vlan_proto == htons(ETH_P_8021Q)) {
1679 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_INCLUDE_VLAN_TAG;
1680 hdr->hdr.l3.vlan_id = ntohs(veth->h_vlan_TCI);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001681 }
1682
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001683 rcu_read_lock();
Julian Wiedmann980f4562019-06-27 17:01:32 +02001684 dst = qeth_dst_check_rcu(skb, ipv);
Julian Wiedmann0cd6783d32019-06-05 13:48:49 +02001685
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001686 if (IS_IQD(card) && skb_get_queue_mapping(skb) != QETH_IQD_MCAST_TXQ)
1687 cast_type = RTN_UNICAST;
1688 else
1689 cast_type = qeth_l3_get_cast_type_rcu(skb, dst, ipv);
1690 l3_hdr->flags |= qeth_l3_cast_type_to_flag(cast_type);
1691
Frank Blaschka4a71df52008-02-15 09:19:42 +01001692 if (ipv == 4) {
Julian Wiedmann1d38c2e2020-05-06 10:09:43 +02001693 l3_hdr->next_hop.addr.s6_addr32[3] =
1694 qeth_next_hop_v4_rcu(skb, dst);
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001695 } else if (ipv == 6) {
Julian Wiedmann1d38c2e2020-05-06 10:09:43 +02001696 l3_hdr->next_hop.addr = *qeth_next_hop_v6_rcu(skb, dst);
David Miller87e75972012-02-01 10:49:17 +00001697
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001698 hdr->hdr.l3.flags |= QETH_HDR_IPV6;
Julian Wiedmann379ac992019-04-25 18:25:57 +02001699 if (!IS_IQD(card))
Julian Wiedmann910a0a82017-12-20 20:11:07 +01001700 hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU;
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001701 } else {
1702 /* OSA only: */
1703 l3_hdr->flags |= QETH_HDR_PASSTHRU;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001704 }
Frank Blaschka1d36cb42011-11-15 02:31:15 +00001705 rcu_read_unlock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01001706}
1707
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02001708static void qeth_l3_fixup_headers(struct sk_buff *skb)
1709{
1710 struct iphdr *iph = ip_hdr(skb);
1711
1712 /* this is safe, IPv6 traffic takes a different path */
1713 if (skb->ip_summed == CHECKSUM_PARTIAL)
1714 iph->check = 0;
Julian Wiedmanne517b642018-09-17 17:36:02 +02001715 if (skb_is_gso(skb)) {
1716 iph->tot_len = 0;
1717 tcp_hdr(skb)->check = ~tcp_v4_check(0, iph->saddr,
1718 iph->daddr, 0);
1719 }
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02001720}
1721
Julian Wiedmann356156b2018-09-17 17:36:03 +02001722static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001723 struct qeth_qdio_out_q *queue, int ipv)
Julian Wiedmanna647a022018-07-11 17:42:46 +02001724{
Julian Wiedmann81ec5432018-11-08 15:06:17 +01001725 unsigned int hw_hdr_len;
1726 int rc;
Julian Wiedmanne517b642018-09-17 17:36:02 +02001727
Julian Wiedmanna647a022018-07-11 17:42:46 +02001728 /* re-use the L2 header area for the HW header: */
Julian Wiedmann81ec5432018-11-08 15:06:17 +01001729 hw_hdr_len = skb_is_gso(skb) ? sizeof(struct qeth_hdr_tso) :
1730 sizeof(struct qeth_hdr);
Julian Wiedmanna647a022018-07-11 17:42:46 +02001731 rc = skb_cow_head(skb, hw_hdr_len - ETH_HLEN);
1732 if (rc)
1733 return rc;
Julian Wiedmanna647a022018-07-11 17:42:46 +02001734 skb_pull(skb, ETH_HLEN);
Julian Wiedmanna647a022018-07-11 17:42:46 +02001735
Julian Wiedmann2d3986d2018-09-17 17:36:00 +02001736 qeth_l3_fixup_headers(skb);
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001737 return qeth_xmit(card, skb, queue, ipv, qeth_l3_fill_header);
Julian Wiedmanna647a022018-07-11 17:42:46 +02001738}
1739
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02001740static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
1741 struct net_device *dev)
1742{
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02001743 struct qeth_card *card = dev->ml_priv;
Julian Wiedmann3a18d752019-04-17 18:17:32 +02001744 u16 txq = skb_get_queue_mapping(skb);
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02001745 int ipv = qeth_get_ip_version(skb);
1746 struct qeth_qdio_out_q *queue;
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001747 int rc;
Julian Wiedmannb0abc4f2019-02-15 19:22:29 +01001748
Julian Wiedmanneeac0e22019-08-23 11:48:49 +02001749 if (!skb_is_gso(skb))
1750 qdisc_skb_cb(skb)->pkt_len = skb->len;
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02001751 if (IS_IQD(card)) {
Julian Wiedmann3a18d752019-04-17 18:17:32 +02001752 queue = card->qdio.out_qs[qeth_iqd_translate_txq(dev, txq)];
1753
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02001754 if (card->options.sniffer)
1755 goto tx_drop;
1756 if ((card->options.cq != QETH_CQ_ENABLED && !ipv) ||
1757 (card->options.cq == QETH_CQ_ENABLED &&
1758 skb->protocol != htons(ETH_P_AF_IUCV)))
Frank Blaschka4a71df52008-02-15 09:19:42 +01001759 goto tx_drop;
Julian Wiedmann3a18d752019-04-17 18:17:32 +02001760 } else {
Julian Wiedmann73dc2da2019-04-17 18:17:33 +02001761 queue = card->qdio.out_qs[txq];
Frank Blaschka4a71df52008-02-15 09:19:42 +01001762 }
1763
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001764 if (!(dev->flags & IFF_BROADCAST) &&
1765 qeth_l3_get_cast_type(skb) == RTN_BROADCAST)
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02001766 goto tx_drop;
1767
Julian Wiedmann356156b2018-09-17 17:36:03 +02001768 if (ipv == 4 || IS_IQD(card))
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001769 rc = qeth_l3_xmit(card, skb, queue, ipv);
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001770 else
Julian Wiedmanneca1d5c2019-06-27 17:01:33 +02001771 rc = qeth_xmit(card, skb, queue, ipv, qeth_l3_fill_header);
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02001772
Julian Wiedmanneeac0e22019-08-23 11:48:49 +02001773 if (!rc)
Julian Wiedmannea1d4a02018-07-11 17:42:45 +02001774 return NETDEV_TX_OK;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001775
1776tx_drop:
Julian Wiedmannb0abc4f2019-02-15 19:22:29 +01001777 QETH_TXQ_STAT_INC(queue, tx_dropped);
Julian Wiedmann104b4852019-03-18 16:40:56 +01001778 kfree_skb(skb);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001779 return NETDEV_TX_OK;
1780}
1781
Julian Wiedmannd0c74822019-03-28 16:39:19 +01001782static void qeth_l3_set_rx_mode(struct net_device *dev)
1783{
1784 struct qeth_card *card = dev->ml_priv;
1785
1786 schedule_work(&card->rx_mode_work);
1787}
1788
Frank Blaschka4a71df52008-02-15 09:19:42 +01001789/*
1790 * we need NOARP for IPv4 but we want neighbor solicitation for IPv6. Setting
1791 * NOARP on the netdevice is no option because it also turns off neighbor
1792 * solicitation. For IPv4 we install a neighbor_setup function. We don't want
1793 * arp resolution but we want the hard header (packet socket will work
1794 * e.g. tcpdump)
1795 */
1796static int qeth_l3_neigh_setup_noarp(struct neighbour *n)
1797{
1798 n->nud_state = NUD_NOARP;
1799 memcpy(n->ha, "FAKELL", 6);
1800 n->output = n->ops->connected_output;
1801 return 0;
1802}
1803
1804static int
1805qeth_l3_neigh_setup(struct net_device *dev, struct neigh_parms *np)
1806{
1807 if (np->tbl->family == AF_INET)
1808 np->neigh_setup = qeth_l3_neigh_setup_noarp;
1809
1810 return 0;
1811}
1812
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001813static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb,
1814 struct net_device *dev,
1815 netdev_features_t features)
1816{
1817 if (qeth_get_ip_version(skb) != 4)
1818 features &= ~NETIF_F_HW_VLAN_CTAG_TX;
1819 return qeth_features_check(skb, dev, features);
1820}
1821
Julian Wiedmann3a18d752019-04-17 18:17:32 +02001822static u16 qeth_l3_iqd_select_queue(struct net_device *dev, struct sk_buff *skb,
1823 struct net_device *sb_dev)
1824{
1825 return qeth_iqd_select_queue(dev, skb, qeth_l3_get_cast_type(skb),
1826 sb_dev);
1827}
1828
Julian Wiedmann73dc2da2019-04-17 18:17:33 +02001829static u16 qeth_l3_osa_select_queue(struct net_device *dev, struct sk_buff *skb,
1830 struct net_device *sb_dev)
1831{
1832 struct qeth_card *card = dev->ml_priv;
1833
Julian Wiedmann1c103cf2020-03-18 13:54:47 +01001834 return IS_VM_NIC(card) ? netdev_pick_tx(dev, skb, sb_dev) :
1835 qeth_get_priority_queue(card, skb);
Julian Wiedmann73dc2da2019-04-17 18:17:33 +02001836}
1837
Frank Blaschka3d58cef2009-01-09 03:44:00 +00001838static const struct net_device_ops qeth_l3_netdev_ops = {
Julian Wiedmanne22355e2019-01-25 15:44:18 +01001839 .ndo_open = qeth_open,
1840 .ndo_stop = qeth_stop,
Julian Wiedmannb0abc4f2019-02-15 19:22:29 +01001841 .ndo_get_stats64 = qeth_get_stats64,
Frank Blaschka8403b132009-01-08 10:50:55 -08001842 .ndo_start_xmit = qeth_l3_hard_start_xmit,
Julian Wiedmann3a18d752019-04-17 18:17:32 +02001843 .ndo_select_queue = qeth_l3_iqd_select_queue,
Frank Blaschka8403b132009-01-08 10:50:55 -08001844 .ndo_validate_addr = eth_validate_addr,
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001845 .ndo_set_rx_mode = qeth_l3_set_rx_mode,
Julian Wiedmann942d6982017-04-11 16:11:10 +02001846 .ndo_do_ioctl = qeth_do_ioctl,
Thomas Richter8f43fb02016-06-16 16:18:59 +02001847 .ndo_fix_features = qeth_fix_features,
1848 .ndo_set_features = qeth_set_features,
Frank Blaschka8403b132009-01-08 10:50:55 -08001849 .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
1850 .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001851 .ndo_tx_timeout = qeth_tx_timeout,
Frank Blaschka8403b132009-01-08 10:50:55 -08001852};
1853
Frank Blaschka3d58cef2009-01-09 03:44:00 +00001854static const struct net_device_ops qeth_l3_osa_netdev_ops = {
Julian Wiedmanne22355e2019-01-25 15:44:18 +01001855 .ndo_open = qeth_open,
1856 .ndo_stop = qeth_stop,
Julian Wiedmannb0abc4f2019-02-15 19:22:29 +01001857 .ndo_get_stats64 = qeth_get_stats64,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00001858 .ndo_start_xmit = qeth_l3_hard_start_xmit,
Julian Wiedmannf13ade12018-09-17 17:35:56 +02001859 .ndo_features_check = qeth_l3_osa_features_check,
Julian Wiedmann73dc2da2019-04-17 18:17:33 +02001860 .ndo_select_queue = qeth_l3_osa_select_queue,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00001861 .ndo_validate_addr = eth_validate_addr,
Julian Wiedmann00c163f2017-12-20 20:11:02 +01001862 .ndo_set_rx_mode = qeth_l3_set_rx_mode,
Julian Wiedmann942d6982017-04-11 16:11:10 +02001863 .ndo_do_ioctl = qeth_do_ioctl,
Thomas Richter8f43fb02016-06-16 16:18:59 +02001864 .ndo_fix_features = qeth_fix_features,
1865 .ndo_set_features = qeth_set_features,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00001866 .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
1867 .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
Jiri Pirko7ff0bcf2011-07-20 04:54:41 +00001868 .ndo_tx_timeout = qeth_tx_timeout,
Frank Blaschka3d58cef2009-01-09 03:44:00 +00001869 .ndo_neigh_setup = qeth_l3_neigh_setup,
1870};
1871
Julian Wiedmanncd652be2020-03-18 13:54:55 +01001872static int qeth_l3_setup_netdev(struct qeth_card *card)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001873{
Julian Wiedmann8ec1e242020-03-25 10:35:01 +01001874 struct net_device *dev = card->dev;
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02001875 unsigned int headroom;
Thomas Richter1aec42b2015-01-21 13:39:10 +01001876 int rc;
1877
Julian Wiedmann1c103cf2020-03-18 13:54:47 +01001878 rc = qeth_setup_netdev(card);
1879 if (rc)
1880 return rc;
1881
Julian Wiedmann379ac992019-04-25 18:25:57 +02001882 if (IS_OSD(card) || IS_OSX(card)) {
Kittipon Meesompop1b811432018-04-26 09:42:16 +02001883 card->dev->netdev_ops = &qeth_l3_osa_netdev_ops;
Julian Wiedmann0f342942018-03-09 18:12:54 +01001884
Kittipon Meesompop1b811432018-04-26 09:42:16 +02001885 /*IPv6 address autoconfiguration stuff*/
Julian Wiedmann8ec1e242020-03-25 10:35:01 +01001886 dev->dev_id = qeth_l3_get_unique_id(card, dev->dev_id);
Julian Wiedmann0f342942018-03-09 18:12:54 +01001887
Julian Wiedmann379ac992019-04-25 18:25:57 +02001888 if (!IS_VM_NIC(card)) {
Kittipon Meesompop1b811432018-04-26 09:42:16 +02001889 card->dev->features |= NETIF_F_SG;
1890 card->dev->hw_features |= NETIF_F_TSO |
1891 NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
1892 card->dev->vlan_features |= NETIF_F_TSO |
1893 NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001894 }
Kittipon Meesompop571f9dd82018-04-26 09:42:22 +02001895
1896 if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) {
1897 card->dev->hw_features |= NETIF_F_IPV6_CSUM;
1898 card->dev->vlan_features |= NETIF_F_IPV6_CSUM;
1899 }
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02001900 if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
1901 card->dev->hw_features |= NETIF_F_TSO6;
1902 card->dev->vlan_features |= NETIF_F_TSO6;
1903 }
1904
1905 /* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */
1906 if (card->dev->hw_features & NETIF_F_TSO6)
1907 headroom = sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
1908 else if (card->dev->hw_features & NETIF_F_TSO)
1909 headroom = sizeof(struct qeth_hdr_tso);
1910 else
1911 headroom = sizeof(struct qeth_hdr) + VLAN_HLEN;
Julian Wiedmann379ac992019-04-25 18:25:57 +02001912 } else if (IS_IQD(card)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001913 card->dev->flags |= IFF_NOARP;
Frank Blaschka3d58cef2009-01-09 03:44:00 +00001914 card->dev->netdev_ops = &qeth_l3_netdev_ops;
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02001915 headroom = sizeof(struct qeth_hdr) - ETH_HLEN;
Julian Wiedmanna647a022018-07-11 17:42:46 +02001916
Thomas Richter1aec42b2015-01-21 13:39:10 +01001917 rc = qeth_l3_iqd_read_initial_mac(card);
1918 if (rc)
Julian Wiedmanncd652be2020-03-18 13:54:55 +01001919 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001920 } else
1921 return -ENODEV;
1922
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02001923 card->dev->needed_headroom = headroom;
Patrick McHardyf6469682013-04-19 02:04:27 +00001924 card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
1925 NETIF_F_HW_VLAN_CTAG_RX |
1926 NETIF_F_HW_VLAN_CTAG_FILTER;
Julian Wiedmanna647a022018-07-11 17:42:46 +02001927
Eric Dumazet02875872014-10-05 18:38:35 -07001928 netif_keep_dst(card->dev);
Julian Wiedmann82bf5c02018-10-12 17:27:14 +02001929 if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6))
Julian Wiedmann371a1e72018-07-11 17:42:44 +02001930 netif_set_gso_max_size(card->dev,
1931 PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS(card) - 1));
Frank Blaschka4a71df52008-02-15 09:19:42 +01001932
Julian Wiedmannd73ef322017-04-11 16:11:11 +02001933 netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
Julian Wiedmanncd652be2020-03-18 13:54:55 +01001934 return register_netdev(card->dev);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001935}
1936
Ursula Braun79a04e42017-06-06 14:33:49 +02001937static const struct device_type qeth_l3_devtype = {
1938 .name = "qeth_layer3",
1939 .groups = qeth_l3_attr_groups,
1940};
1941
Frank Blaschka4a71df52008-02-15 09:19:42 +01001942static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
1943{
1944 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
Ursula Braun9111e782017-05-10 19:07:51 +02001945 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001946
Julian Wiedmann7221b722019-03-18 16:40:55 +01001947 hash_init(card->ip_htable);
Julian Wiedmanndf2a2a52019-03-28 16:39:23 +01001948 mutex_init(&card->ip_lock);
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01001949 card->cmd_wq = alloc_ordered_workqueue("%s_cmd", 0,
1950 dev_name(&gdev->dev));
1951 if (!card->cmd_wq)
1952 return -ENOMEM;
Julian Wiedmann7221b722019-03-18 16:40:55 +01001953
Ursula Braun79a04e42017-06-06 14:33:49 +02001954 if (gdev->dev.type == &qeth_generic_devtype) {
1955 rc = qeth_l3_create_device_attributes(&gdev->dev);
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01001956 if (rc) {
1957 destroy_workqueue(card->cmd_wq);
Ursula Braun79a04e42017-06-06 14:33:49 +02001958 return rc;
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01001959 }
Ursula Braun79a04e42017-06-06 14:33:49 +02001960 }
Julian Wiedmann7221b722019-03-18 16:40:55 +01001961
Julian Wiedmannd0c74822019-03-28 16:39:19 +01001962 INIT_WORK(&card->rx_mode_work, qeth_l3_rx_mode_work);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001963 return 0;
1964}
1965
1966static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
1967{
1968 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
1969
Ursula Braun79a04e42017-06-06 14:33:49 +02001970 if (cgdev->dev.type == &qeth_generic_devtype)
1971 qeth_l3_remove_device_attributes(&cgdev->dev);
Ursula Braun9dc48cc2010-07-22 23:15:05 +00001972
Ursula Braunf2148562009-05-19 21:38:37 +00001973 qeth_set_allowed_threads(card, 0, 1);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001974 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
1975
Ursula Braun70919e22011-02-26 22:41:36 -08001976 if (cgdev->state == CCWGROUP_ONLINE)
Julian Wiedmann91003f32020-01-25 16:53:01 +01001977 qeth_set_offline(card, false);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001978
Julian Wiedmannc2780c12019-02-04 17:40:08 +01001979 cancel_work_sync(&card->close_dev_work);
Julian Wiedmanncd652be2020-03-18 13:54:55 +01001980 if (card->dev->reg_state == NETREG_REGISTERED)
Julian Wiedmann30356d02018-11-02 19:04:10 +01001981 unregister_netdev(card->dev);
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01001982
1983 flush_workqueue(card->cmd_wq);
1984 destroy_workqueue(card->cmd_wq);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02001985 qeth_l3_clear_ip_htable(card, 0);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001986 qeth_l3_clear_ipato_list(card);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001987}
1988
Julian Wiedmannb7ea0412020-09-23 10:36:58 +02001989static int qeth_l3_set_online(struct qeth_card *card, bool carrier_ok)
Frank Blaschka4a71df52008-02-15 09:19:42 +01001990{
Julian Wiedmannfa3d2e62019-01-25 15:44:21 +01001991 struct net_device *dev = card->dev;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001992 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001993
1994 /* softsetup */
Julian Wiedmann57a688aa2019-06-11 18:37:55 +02001995 QETH_CARD_TEXT(card, 2, "softsetp");
Frank Blaschka4a71df52008-02-15 09:19:42 +01001996
Frank Blaschka4a71df52008-02-15 09:19:42 +01001997 rc = qeth_l3_setadapter_parms(card);
1998 if (rc)
Julian Wiedmann57a688aa2019-06-11 18:37:55 +02001999 QETH_CARD_TEXT_(card, 2, "2err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002000 if (!card->options.sniffer) {
Julian Wiedmann17d97232020-01-25 16:53:03 +01002001 qeth_l3_start_ipassists(card);
2002
Ursula Braun76b11f82010-01-11 02:50:50 +00002003 rc = qeth_l3_setrouting_v4(card);
2004 if (rc)
Julian Wiedmann57a688aa2019-06-11 18:37:55 +02002005 QETH_CARD_TEXT_(card, 2, "4err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002006 rc = qeth_l3_setrouting_v6(card);
2007 if (rc)
Julian Wiedmann57a688aa2019-06-11 18:37:55 +02002008 QETH_CARD_TEXT_(card, 2, "5err%04x", rc);
Ursula Braun76b11f82010-01-11 02:50:50 +00002009 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002010
Frank Blaschka4a71df52008-02-15 09:19:42 +01002011 card->state = CARD_STATE_SOFTSETUP;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002012
2013 qeth_set_allowed_threads(card, 0xffffffff, 0);
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02002014 qeth_l3_recover_ip(card);
Julian Wiedmannd025da92018-06-29 19:45:54 +02002015
Julian Wiedmanncd652be2020-03-18 13:54:55 +01002016 if (dev->reg_state != NETREG_REGISTERED) {
2017 rc = qeth_l3_setup_netdev(card);
Julian Wiedmannfa3d2e62019-01-25 15:44:21 +01002018 if (rc)
Julian Wiedmannf2bcf9d2020-09-23 10:36:59 +02002019 goto err_setup;
Julian Wiedmanncd652be2020-03-18 13:54:55 +01002020
2021 if (carrier_ok)
2022 netif_carrier_on(dev);
Julian Wiedmannfa3d2e62019-01-25 15:44:21 +01002023 } else {
Ursula Braun4763b0a2011-12-19 22:56:32 +00002024 rtnl_lock();
Julian Wiedmannfa3d2e62019-01-25 15:44:21 +01002025 if (carrier_ok)
2026 netif_carrier_on(dev);
2027 else
2028 netif_carrier_off(dev);
2029
Julian Wiedmanne6e771b2019-01-25 15:44:22 +01002030 netif_device_attach(dev);
Julian Wiedmannfa3d2e62019-01-25 15:44:21 +01002031 qeth_enable_hw_features(dev);
2032
Julian Wiedmannd7d543f2019-02-28 18:59:36 +01002033 if (card->info.open_when_online) {
2034 card->info.open_when_online = 0;
Julian Wiedmannd4560152019-02-28 18:59:39 +01002035 dev_open(dev, NULL);
Julian Wiedmann9aa17df2018-07-11 17:42:40 +02002036 }
Ursula Braun4763b0a2011-12-19 22:56:32 +00002037 rtnl_unlock();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002038 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002039 return 0;
Julian Wiedmannb7ea0412020-09-23 10:36:58 +02002040
Julian Wiedmannf2bcf9d2020-09-23 10:36:59 +02002041err_setup:
2042 qeth_set_allowed_threads(card, 0, 1);
2043 card->state = CARD_STATE_DOWN;
2044 qeth_l3_clear_ip_htable(card, 1);
Ursula Braunaa909222009-11-12 00:11:43 +00002045 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002046}
2047
Julian Wiedmann91003f32020-01-25 16:53:01 +01002048static void qeth_l3_set_offline(struct qeth_card *card)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002049{
Julian Wiedmannf2bcf9d2020-09-23 10:36:59 +02002050 qeth_set_allowed_threads(card, 0, 1);
2051 qeth_l3_drain_rx_mode_cache(card);
2052
2053 if (card->options.sniffer &&
2054 (card->info.promisc_mode == SET_PROMISC_MODE_ON))
2055 qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
2056
2057 if (card->state == CARD_STATE_SOFTSETUP) {
2058 card->state = CARD_STATE_DOWN;
2059 qeth_l3_clear_ip_htable(card, 1);
2060 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002061}
2062
Eugene Crosserc044dc22014-01-29 09:23:48 +01002063/* Returns zero if the command is successfully "consumed" */
2064static int qeth_l3_control_event(struct qeth_card *card,
2065 struct qeth_ipa_cmd *cmd)
2066{
2067 return 1;
2068}
2069
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002070struct qeth_discipline qeth_l3_discipline = {
Ursula Braun79a04e42017-06-06 14:33:49 +02002071 .devtype = &qeth_l3_devtype,
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002072 .setup = qeth_l3_probe_device,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002073 .remove = qeth_l3_remove_device,
2074 .set_online = qeth_l3_set_online,
2075 .set_offline = qeth_l3_set_offline,
Julian Wiedmann942d6982017-04-11 16:11:10 +02002076 .do_ioctl = qeth_l3_do_ioctl,
Eugene Crosserc044dc22014-01-29 09:23:48 +01002077 .control_event_handler = qeth_l3_control_event,
Frank Blaschka4a71df52008-02-15 09:19:42 +01002078};
Sebastian Ottc041f2d4872012-05-15 18:02:21 +02002079EXPORT_SYMBOL_GPL(qeth_l3_discipline);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002080
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002081static int qeth_l3_handle_ip_event(struct qeth_card *card,
2082 struct qeth_ipaddr *addr,
2083 unsigned long event)
2084{
2085 switch (event) {
2086 case NETDEV_UP:
Julian Wiedmann05a17852019-03-28 16:39:21 +01002087 qeth_l3_modify_ip(card, addr, true);
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002088 return NOTIFY_OK;
2089 case NETDEV_DOWN:
Julian Wiedmann05a17852019-03-28 16:39:21 +01002090 qeth_l3_modify_ip(card, addr, false);
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002091 return NOTIFY_OK;
2092 default:
2093 return NOTIFY_DONE;
2094 }
2095}
2096
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01002097struct qeth_l3_ip_event_work {
2098 struct work_struct work;
2099 struct qeth_card *card;
2100 struct qeth_ipaddr addr;
2101};
2102
2103#define to_ip_work(w) container_of((w), struct qeth_l3_ip_event_work, work)
2104
2105static void qeth_l3_add_ip_worker(struct work_struct *work)
2106{
2107 struct qeth_l3_ip_event_work *ip_work = to_ip_work(work);
2108
2109 qeth_l3_modify_ip(ip_work->card, &ip_work->addr, true);
2110 kfree(work);
2111}
2112
2113static void qeth_l3_delete_ip_worker(struct work_struct *work)
2114{
2115 struct qeth_l3_ip_event_work *ip_work = to_ip_work(work);
2116
2117 qeth_l3_modify_ip(ip_work->card, &ip_work->addr, false);
2118 kfree(work);
2119}
2120
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002121static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev)
2122{
2123 if (is_vlan_dev(dev))
2124 dev = vlan_dev_real_dev(dev);
2125 if (dev->netdev_ops == &qeth_l3_osa_netdev_ops ||
2126 dev->netdev_ops == &qeth_l3_netdev_ops)
2127 return (struct qeth_card *) dev->ml_priv;
2128 return NULL;
2129}
2130
Frank Blaschka4a71df52008-02-15 09:19:42 +01002131static int qeth_l3_ip_event(struct notifier_block *this,
David S. Miller76fef2b2008-03-22 18:22:42 -07002132 unsigned long event, void *ptr)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002133{
Lakhvich Dmitriy5f78e292016-06-16 16:18:58 +02002134
Frank Blaschka4a71df52008-02-15 09:19:42 +01002135 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002136 struct net_device *dev = ifa->ifa_dev->dev;
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002137 struct qeth_ipaddr addr;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002138 struct qeth_card *card;
2139
Frank Blaschka4a71df52008-02-15 09:19:42 +01002140 card = qeth_l3_get_card_from_dev(dev);
2141 if (!card)
2142 return NOTIFY_DONE;
frank.blaschka@de.ibm.com6d8823d2012-05-16 01:28:26 +00002143 QETH_CARD_TEXT(card, 3, "ipevent");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002144
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002145 qeth_l3_init_ipaddr(&addr, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV4);
Julian Wiedmann1b40d4b2019-10-31 13:42:20 +01002146 addr.u.a4.addr = ifa->ifa_address;
Julian Wiedmann490df972019-12-18 17:34:46 +01002147 addr.u.a4.mask = ifa->ifa_mask;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002148
Julian Wiedmannd66b1c02018-03-09 18:13:00 +01002149 return qeth_l3_handle_ip_event(card, &addr, event);
Frank Blaschka4a71df52008-02-15 09:19:42 +01002150}
2151
2152static struct notifier_block qeth_l3_ip_notifier = {
2153 qeth_l3_ip_event,
2154 NULL,
2155};
2156
Frank Blaschka4a71df52008-02-15 09:19:42 +01002157static int qeth_l3_ip6_event(struct notifier_block *this,
David S. Miller76fef2b2008-03-22 18:22:42 -07002158 unsigned long event, void *ptr)
Frank Blaschka4a71df52008-02-15 09:19:42 +01002159{
2160 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
Julian Wiedmannb9caa982018-03-09 18:13:01 +01002161 struct net_device *dev = ifa->idev->dev;
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01002162 struct qeth_l3_ip_event_work *ip_work;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002163 struct qeth_card *card;
2164
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01002165 if (event != NETDEV_UP && event != NETDEV_DOWN)
2166 return NOTIFY_DONE;
2167
Frank Blaschka4a71df52008-02-15 09:19:42 +01002168 card = qeth_l3_get_card_from_dev(dev);
2169 if (!card)
2170 return NOTIFY_DONE;
Carsten Otte847a50f2010-06-21 22:57:05 +00002171 QETH_CARD_TEXT(card, 3, "ip6event");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002172 if (!qeth_is_supported(card, IPA_IPV6))
2173 return NOTIFY_DONE;
2174
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01002175 ip_work = kmalloc(sizeof(*ip_work), GFP_ATOMIC);
2176 if (!ip_work)
2177 return NOTIFY_DONE;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002178
Julian Wiedmann7686e4b2019-03-28 16:39:22 +01002179 if (event == NETDEV_UP)
2180 INIT_WORK(&ip_work->work, qeth_l3_add_ip_worker);
2181 else
2182 INIT_WORK(&ip_work->work, qeth_l3_delete_ip_worker);
2183
2184 ip_work->card = card;
2185 qeth_l3_init_ipaddr(&ip_work->addr, QETH_IP_TYPE_NORMAL,
2186 QETH_PROT_IPV6);
2187 ip_work->addr.u.a6.addr = ifa->addr;
2188 ip_work->addr.u.a6.pfxlen = ifa->prefix_len;
2189
2190 queue_work(card->cmd_wq, &ip_work->work);
2191 return NOTIFY_OK;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002192}
2193
2194static struct notifier_block qeth_l3_ip6_notifier = {
2195 qeth_l3_ip6_event,
2196 NULL,
2197};
Frank Blaschka4a71df52008-02-15 09:19:42 +01002198
2199static int qeth_l3_register_notifiers(void)
2200{
2201 int rc;
2202
Carsten Otte847a50f2010-06-21 22:57:05 +00002203 QETH_DBF_TEXT(SETUP, 5, "regnotif");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002204 rc = register_inetaddr_notifier(&qeth_l3_ip_notifier);
2205 if (rc)
2206 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +01002207 rc = register_inet6addr_notifier(&qeth_l3_ip6_notifier);
2208 if (rc) {
2209 unregister_inetaddr_notifier(&qeth_l3_ip_notifier);
2210 return rc;
2211 }
Frank Blaschka4a71df52008-02-15 09:19:42 +01002212 return 0;
2213}
2214
2215static void qeth_l3_unregister_notifiers(void)
2216{
Carsten Otte847a50f2010-06-21 22:57:05 +00002217 QETH_DBF_TEXT(SETUP, 5, "unregnot");
Stefan Raspl18af5c12012-11-19 02:46:50 +00002218 WARN_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier));
Stefan Raspl18af5c12012-11-19 02:46:50 +00002219 WARN_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier));
Frank Blaschka4a71df52008-02-15 09:19:42 +01002220}
2221
2222static int __init qeth_l3_init(void)
2223{
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002224 pr_info("register layer 3 discipline\n");
Julian Wiedmannc0622042017-12-20 20:10:58 +01002225 return qeth_l3_register_notifiers();
Frank Blaschka4a71df52008-02-15 09:19:42 +01002226}
2227
2228static void __exit qeth_l3_exit(void)
2229{
2230 qeth_l3_unregister_notifiers();
Frank Blaschka74eacdb2008-12-25 13:39:49 +01002231 pr_info("unregister layer 3 discipline\n");
Frank Blaschka4a71df52008-02-15 09:19:42 +01002232}
2233
2234module_init(qeth_l3_init);
2235module_exit(qeth_l3_exit);
2236MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
2237MODULE_DESCRIPTION("qeth layer 3 discipline");
2238MODULE_LICENSE("GPL");