blob: c4dcd667c894538f67b2e80fb058040b0c3f0262 [file] [log] [blame]
Frank Blaschka4a71df52008-02-15 09:19:42 +01001/*
Frank Blaschka4a71df52008-02-15 09:19:42 +01002 * Copyright IBM Corp. 2007
3 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
4 * Frank Pavlic <fpavlic@de.ibm.com>,
5 * Thomas Spatzier <tspat@de.ibm.com>,
6 * Frank Blaschka <frank.blaschka@de.ibm.com>
7 */
8
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09009#include <linux/slab.h>
Frank Blaschkab3332932011-08-08 01:33:59 +000010#include <asm/ebcdic.h>
Frank Blaschka4a71df52008-02-15 09:19:42 +010011#include "qeth_l3.h"
12
13#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
14struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
15
Frank Blaschka4a71df52008-02-15 09:19:42 +010016static ssize_t qeth_l3_dev_route_show(struct qeth_card *card,
17 struct qeth_routing_info *route, char *buf)
18{
19 switch (route->type) {
20 case PRIMARY_ROUTER:
21 return sprintf(buf, "%s\n", "primary router");
22 case SECONDARY_ROUTER:
23 return sprintf(buf, "%s\n", "secondary router");
24 case MULTICAST_ROUTER:
25 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
26 return sprintf(buf, "%s\n", "multicast router+");
27 else
28 return sprintf(buf, "%s\n", "multicast router");
29 case PRIMARY_CONNECTOR:
30 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
31 return sprintf(buf, "%s\n", "primary connector+");
32 else
33 return sprintf(buf, "%s\n", "primary connector");
34 case SECONDARY_CONNECTOR:
35 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
36 return sprintf(buf, "%s\n", "secondary connector+");
37 else
38 return sprintf(buf, "%s\n", "secondary connector");
39 default:
40 return sprintf(buf, "%s\n", "no");
41 }
42}
43
44static ssize_t qeth_l3_dev_route4_show(struct device *dev,
45 struct device_attribute *attr, char *buf)
46{
47 struct qeth_card *card = dev_get_drvdata(dev);
48
49 if (!card)
50 return -EINVAL;
51
52 return qeth_l3_dev_route_show(card, &card->options.route4, buf);
53}
54
55static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
56 struct qeth_routing_info *route, enum qeth_prot_versions prot,
57 const char *buf, size_t count)
58{
59 enum qeth_routing_types old_route_type = route->type;
60 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +000061 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +010062
63 tmp = strsep((char **) &buf, "\n");
Frank Blaschkac4949f02010-05-11 19:34:47 +000064 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +010065 if (!strcmp(tmp, "no_router")) {
66 route->type = NO_ROUTER;
67 } else if (!strcmp(tmp, "primary_connector")) {
68 route->type = PRIMARY_CONNECTOR;
69 } else if (!strcmp(tmp, "secondary_connector")) {
70 route->type = SECONDARY_CONNECTOR;
71 } else if (!strcmp(tmp, "primary_router")) {
72 route->type = PRIMARY_ROUTER;
73 } else if (!strcmp(tmp, "secondary_router")) {
74 route->type = SECONDARY_ROUTER;
75 } else if (!strcmp(tmp, "multicast_router")) {
76 route->type = MULTICAST_ROUTER;
77 } else {
Frank Blaschkac4949f02010-05-11 19:34:47 +000078 rc = -EINVAL;
79 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +010080 }
Eugene Crosserc3521252015-01-16 14:05:47 +010081 if (qeth_card_hw_is_reachable(card) &&
Frank Blaschka4a71df52008-02-15 09:19:42 +010082 (old_route_type != route->type)) {
83 if (prot == QETH_PROT_IPV4)
84 rc = qeth_l3_setrouting_v4(card);
85 else if (prot == QETH_PROT_IPV6)
86 rc = qeth_l3_setrouting_v6(card);
87 }
Frank Blaschkac4949f02010-05-11 19:34:47 +000088out:
Stefan Raspl82e2e782013-03-18 20:04:43 +000089 if (rc)
90 route->type = old_route_type;
Frank Blaschkac4949f02010-05-11 19:34:47 +000091 mutex_unlock(&card->conf_mutex);
92 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +010093}
94
95static ssize_t qeth_l3_dev_route4_store(struct device *dev,
96 struct device_attribute *attr, const char *buf, size_t count)
97{
98 struct qeth_card *card = dev_get_drvdata(dev);
99
100 if (!card)
101 return -EINVAL;
102
103 return qeth_l3_dev_route_store(card, &card->options.route4,
104 QETH_PROT_IPV4, buf, count);
105}
106
107static DEVICE_ATTR(route4, 0644, qeth_l3_dev_route4_show,
108 qeth_l3_dev_route4_store);
109
110static ssize_t qeth_l3_dev_route6_show(struct device *dev,
111 struct device_attribute *attr, char *buf)
112{
113 struct qeth_card *card = dev_get_drvdata(dev);
114
115 if (!card)
116 return -EINVAL;
117
Frank Blaschka4a71df52008-02-15 09:19:42 +0100118 return qeth_l3_dev_route_show(card, &card->options.route6, buf);
119}
120
121static ssize_t qeth_l3_dev_route6_store(struct device *dev,
122 struct device_attribute *attr, const char *buf, size_t count)
123{
124 struct qeth_card *card = dev_get_drvdata(dev);
125
126 if (!card)
127 return -EINVAL;
128
Frank Blaschka4a71df52008-02-15 09:19:42 +0100129 return qeth_l3_dev_route_store(card, &card->options.route6,
130 QETH_PROT_IPV6, buf, count);
131}
132
133static DEVICE_ATTR(route6, 0644, qeth_l3_dev_route6_show,
134 qeth_l3_dev_route6_store);
135
136static ssize_t qeth_l3_dev_fake_broadcast_show(struct device *dev,
137 struct device_attribute *attr, char *buf)
138{
139 struct qeth_card *card = dev_get_drvdata(dev);
140
141 if (!card)
142 return -EINVAL;
143
144 return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0);
145}
146
147static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev,
148 struct device_attribute *attr, const char *buf, size_t count)
149{
150 struct qeth_card *card = dev_get_drvdata(dev);
151 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000152 int i, rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100153
154 if (!card)
155 return -EINVAL;
156
Frank Blaschkac4949f02010-05-11 19:34:47 +0000157 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100158 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000159 (card->state != CARD_STATE_RECOVER)) {
160 rc = -EPERM;
161 goto out;
162 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100163
164 i = simple_strtoul(buf, &tmp, 16);
165 if ((i == 0) || (i == 1))
166 card->options.fake_broadcast = i;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000167 else
168 rc = -EINVAL;
169out:
170 mutex_unlock(&card->conf_mutex);
171 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100172}
173
174static DEVICE_ATTR(fake_broadcast, 0644, qeth_l3_dev_fake_broadcast_show,
175 qeth_l3_dev_fake_broadcast_store);
176
Ursula Braun76b11f82010-01-11 02:50:50 +0000177static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
178 struct device_attribute *attr, char *buf)
179{
180 struct qeth_card *card = dev_get_drvdata(dev);
181
182 if (!card)
183 return -EINVAL;
184
185 return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
186}
187
188static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
189 struct device_attribute *attr, const char *buf, size_t count)
190{
191 struct qeth_card *card = dev_get_drvdata(dev);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000192 int rc = 0;
Ursula Braun76b11f82010-01-11 02:50:50 +0000193 unsigned long i;
194
195 if (!card)
196 return -EINVAL;
197
198 if (card->info.type != QETH_CARD_TYPE_IQD)
199 return -EPERM;
Frank Blaschkab3332932011-08-08 01:33:59 +0000200 if (card->options.cq == QETH_CQ_ENABLED)
201 return -EPERM;
Ursula Braun76b11f82010-01-11 02:50:50 +0000202
Frank Blaschkac4949f02010-05-11 19:34:47 +0000203 mutex_lock(&card->conf_mutex);
Ursula Braun76b11f82010-01-11 02:50:50 +0000204 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000205 (card->state != CARD_STATE_RECOVER)) {
206 rc = -EPERM;
207 goto out;
208 }
Ursula Braun76b11f82010-01-11 02:50:50 +0000209
Jingoo Han01787222013-07-22 10:18:15 +0900210 rc = kstrtoul(buf, 16, &i);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000211 if (rc) {
212 rc = -EINVAL;
213 goto out;
214 }
Ursula Braun76b11f82010-01-11 02:50:50 +0000215 switch (i) {
216 case 0:
217 card->options.sniffer = i;
218 break;
219 case 1:
Frank Blaschkac4949f02010-05-11 19:34:47 +0000220 qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
Ursula Braun76b11f82010-01-11 02:50:50 +0000221 if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) {
222 card->options.sniffer = i;
223 if (card->qdio.init_pool.buf_count !=
224 QETH_IN_BUF_COUNT_MAX)
225 qeth_realloc_buffer_pool(card,
226 QETH_IN_BUF_COUNT_MAX);
Ursula Braun76b11f82010-01-11 02:50:50 +0000227 } else
Frank Blaschkac4949f02010-05-11 19:34:47 +0000228 rc = -EPERM;
Ursula Braun6cc31d02011-11-15 02:31:12 +0000229 break;
230 default:
Frank Blaschkac4949f02010-05-11 19:34:47 +0000231 rc = -EINVAL;
Ursula Braun76b11f82010-01-11 02:50:50 +0000232 }
Frank Blaschkac4949f02010-05-11 19:34:47 +0000233out:
234 mutex_unlock(&card->conf_mutex);
235 return rc ? rc : count;
Ursula Braun76b11f82010-01-11 02:50:50 +0000236}
237
238static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
239 qeth_l3_dev_sniffer_store);
240
Frank Blaschkab3332932011-08-08 01:33:59 +0000241
242static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
243 struct device_attribute *attr, char *buf)
244{
245 struct qeth_card *card = dev_get_drvdata(dev);
246 char tmp_hsuid[9];
247
248 if (!card)
249 return -EINVAL;
250
251 if (card->info.type != QETH_CARD_TYPE_IQD)
252 return -EPERM;
253
254 if (card->state == CARD_STATE_DOWN)
255 return -EPERM;
256
257 memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid));
258 EBCASC(tmp_hsuid, 8);
259 return sprintf(buf, "%s\n", tmp_hsuid);
260}
261
262static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
263 struct device_attribute *attr, const char *buf, size_t count)
264{
265 struct qeth_card *card = dev_get_drvdata(dev);
266 struct qeth_ipaddr *addr;
267 char *tmp;
268 int i;
269
270 if (!card)
271 return -EINVAL;
272
273 if (card->info.type != QETH_CARD_TYPE_IQD)
274 return -EPERM;
275 if (card->state != CARD_STATE_DOWN &&
276 card->state != CARD_STATE_RECOVER)
277 return -EPERM;
278 if (card->options.sniffer)
279 return -EPERM;
280 if (card->options.cq == QETH_CQ_NOTAVAILABLE)
281 return -EPERM;
282
283 tmp = strsep((char **)&buf, "\n");
284 if (strlen(tmp) > 8)
285 return -EINVAL;
286
287 if (card->options.hsuid[0]) {
288 /* delete old ip address */
289 addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
290 if (addr != NULL) {
291 addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
292 addr->u.a6.addr.s6_addr32[1] = 0x00000000;
293 for (i = 8; i < 16; i++)
294 addr->u.a6.addr.s6_addr[i] =
295 card->options.hsuid[i - 8];
296 addr->u.a6.pfxlen = 0;
297 addr->type = QETH_IP_TYPE_NORMAL;
298 } else
299 return -ENOMEM;
300 if (!qeth_l3_delete_ip(card, addr))
301 kfree(addr);
302 qeth_l3_set_ip_addr_list(card);
303 }
304
305 if (strlen(tmp) == 0) {
306 /* delete ip address only */
307 card->options.hsuid[0] = '\0';
308 if (card->dev)
309 memcpy(card->dev->perm_addr, card->options.hsuid, 9);
310 qeth_configure_cq(card, QETH_CQ_DISABLED);
311 return count;
312 }
313
314 if (qeth_configure_cq(card, QETH_CQ_ENABLED))
315 return -EPERM;
316
Kees Cook096a8aa2013-07-03 15:04:55 -0700317 snprintf(card->options.hsuid, sizeof(card->options.hsuid),
318 "%-8s", tmp);
Frank Blaschkab3332932011-08-08 01:33:59 +0000319 ASCEBC(card->options.hsuid, 8);
320 if (card->dev)
321 memcpy(card->dev->perm_addr, card->options.hsuid, 9);
322
323 addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
324 if (addr != NULL) {
325 addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
326 addr->u.a6.addr.s6_addr32[1] = 0x00000000;
327 for (i = 8; i < 16; i++)
328 addr->u.a6.addr.s6_addr[i] = card->options.hsuid[i - 8];
329 addr->u.a6.pfxlen = 0;
330 addr->type = QETH_IP_TYPE_NORMAL;
331 } else
332 return -ENOMEM;
333 if (!qeth_l3_add_ip(card, addr))
334 kfree(addr);
335 qeth_l3_set_ip_addr_list(card);
336
337 return count;
338}
339
340static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show,
341 qeth_l3_dev_hsuid_store);
342
343
Frank Blaschka4a71df52008-02-15 09:19:42 +0100344static struct attribute *qeth_l3_device_attrs[] = {
345 &dev_attr_route4.attr,
346 &dev_attr_route6.attr,
347 &dev_attr_fake_broadcast.attr,
Ursula Braun76b11f82010-01-11 02:50:50 +0000348 &dev_attr_sniffer.attr,
Frank Blaschkab3332932011-08-08 01:33:59 +0000349 &dev_attr_hsuid.attr,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100350 NULL,
351};
352
353static struct attribute_group qeth_l3_device_attr_group = {
354 .attrs = qeth_l3_device_attrs,
355};
356
357static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev,
358 struct device_attribute *attr, char *buf)
359{
360 struct qeth_card *card = dev_get_drvdata(dev);
361
362 if (!card)
363 return -EINVAL;
364
365 return sprintf(buf, "%i\n", card->ipato.enabled? 1:0);
366}
367
368static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
369 struct device_attribute *attr, const char *buf, size_t count)
370{
371 struct qeth_card *card = dev_get_drvdata(dev);
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000372 struct qeth_ipaddr *tmpipa, *t;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100373 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000374 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100375
376 if (!card)
377 return -EINVAL;
378
Frank Blaschkac4949f02010-05-11 19:34:47 +0000379 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100380 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000381 (card->state != CARD_STATE_RECOVER)) {
382 rc = -EPERM;
383 goto out;
384 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100385
386 tmp = strsep((char **) &buf, "\n");
387 if (!strcmp(tmp, "toggle")) {
388 card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
389 } else if (!strcmp(tmp, "1")) {
390 card->ipato.enabled = 1;
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000391 list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
392 if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
393 qeth_l3_is_addr_covered_by_ipato(card, tmpipa))
394 tmpipa->set_flags |=
395 QETH_IPA_SETIP_TAKEOVER_FLAG;
396 }
397
Frank Blaschka4a71df52008-02-15 09:19:42 +0100398 } else if (!strcmp(tmp, "0")) {
399 card->ipato.enabled = 0;
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000400 list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
401 if (tmpipa->set_flags &
402 QETH_IPA_SETIP_TAKEOVER_FLAG)
403 tmpipa->set_flags &=
404 ~QETH_IPA_SETIP_TAKEOVER_FLAG;
405 }
Frank Blaschkac4949f02010-05-11 19:34:47 +0000406 } else
407 rc = -EINVAL;
408out:
409 mutex_unlock(&card->conf_mutex);
410 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100411}
412
413static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
414 qeth_l3_dev_ipato_enable_show,
415 qeth_l3_dev_ipato_enable_store);
416
417static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev,
418 struct device_attribute *attr, char *buf)
419{
420 struct qeth_card *card = dev_get_drvdata(dev);
421
422 if (!card)
423 return -EINVAL;
424
425 return sprintf(buf, "%i\n", card->ipato.invert4? 1:0);
426}
427
428static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
429 struct device_attribute *attr,
430 const char *buf, size_t count)
431{
432 struct qeth_card *card = dev_get_drvdata(dev);
433 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000434 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100435
436 if (!card)
437 return -EINVAL;
438
Frank Blaschkac4949f02010-05-11 19:34:47 +0000439 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100440 tmp = strsep((char **) &buf, "\n");
441 if (!strcmp(tmp, "toggle")) {
442 card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
443 } else if (!strcmp(tmp, "1")) {
444 card->ipato.invert4 = 1;
445 } else if (!strcmp(tmp, "0")) {
446 card->ipato.invert4 = 0;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000447 } else
448 rc = -EINVAL;
449 mutex_unlock(&card->conf_mutex);
450 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100451}
452
453static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
454 qeth_l3_dev_ipato_invert4_show,
455 qeth_l3_dev_ipato_invert4_store);
456
457static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
458 enum qeth_prot_versions proto)
459{
460 struct qeth_ipato_entry *ipatoe;
461 unsigned long flags;
462 char addr_str[40];
463 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
464 int i = 0;
465
466 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
467 /* add strlen for "/<mask>\n" */
468 entry_len += (proto == QETH_PROT_IPV4)? 5 : 6;
469 spin_lock_irqsave(&card->ip_lock, flags);
470 list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
471 if (ipatoe->proto != proto)
472 continue;
473 /* String must not be longer than PAGE_SIZE. So we check if
474 * string length gets near PAGE_SIZE. Then we can savely display
475 * the next IPv6 address (worst case, compared to IPv4) */
476 if ((PAGE_SIZE - i) <= entry_len)
477 break;
478 qeth_l3_ipaddr_to_string(proto, ipatoe->addr, addr_str);
479 i += snprintf(buf + i, PAGE_SIZE - i,
480 "%s/%i\n", addr_str, ipatoe->mask_bits);
481 }
482 spin_unlock_irqrestore(&card->ip_lock, flags);
483 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
484
485 return i;
486}
487
488static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev,
489 struct device_attribute *attr, char *buf)
490{
491 struct qeth_card *card = dev_get_drvdata(dev);
492
493 if (!card)
494 return -EINVAL;
495
496 return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
497}
498
499static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto,
500 u8 *addr, int *mask_bits)
501{
502 const char *start, *end;
503 char *tmp;
504 char buffer[40] = {0, };
505
506 start = buf;
507 /* get address string */
508 end = strchr(start, '/');
509 if (!end || (end - start >= 40)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100510 return -EINVAL;
511 }
512 strncpy(buffer, start, end - start);
513 if (qeth_l3_string_to_ipaddr(buffer, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100514 return -EINVAL;
515 }
516 start = end + 1;
517 *mask_bits = simple_strtoul(start, &tmp, 10);
518 if (!strlen(start) ||
519 (tmp == start) ||
520 (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100521 return -EINVAL;
522 }
523 return 0;
524}
525
526static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count,
527 struct qeth_card *card, enum qeth_prot_versions proto)
528{
529 struct qeth_ipato_entry *ipatoe;
530 u8 addr[16];
531 int mask_bits;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000532 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100533
Frank Blaschkac4949f02010-05-11 19:34:47 +0000534 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100535 rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
536 if (rc)
Frank Blaschkac4949f02010-05-11 19:34:47 +0000537 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100538
539 ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL);
540 if (!ipatoe) {
Frank Blaschkac4949f02010-05-11 19:34:47 +0000541 rc = -ENOMEM;
542 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100543 }
544 ipatoe->proto = proto;
545 memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4)? 4:16);
546 ipatoe->mask_bits = mask_bits;
547
548 rc = qeth_l3_add_ipato_entry(card, ipatoe);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000549 if (rc)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100550 kfree(ipatoe);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000551out:
552 mutex_unlock(&card->conf_mutex);
553 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100554}
555
556static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev,
557 struct device_attribute *attr, const char *buf, size_t count)
558{
559 struct qeth_card *card = dev_get_drvdata(dev);
560
561 if (!card)
562 return -EINVAL;
563
564 return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4);
565}
566
567static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
568 qeth_l3_dev_ipato_add4_show,
569 qeth_l3_dev_ipato_add4_store);
570
571static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
572 struct qeth_card *card, enum qeth_prot_versions proto)
573{
574 u8 addr[16];
575 int mask_bits;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000576 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100577
Frank Blaschkac4949f02010-05-11 19:34:47 +0000578 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100579 rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000580 if (!rc)
581 qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
582 mutex_unlock(&card->conf_mutex);
583 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100584}
585
586static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev,
587 struct device_attribute *attr, const char *buf, size_t count)
588{
589 struct qeth_card *card = dev_get_drvdata(dev);
590
591 if (!card)
592 return -EINVAL;
593
594 return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4);
595}
596
597static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL,
598 qeth_l3_dev_ipato_del4_store);
599
600static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev,
601 struct device_attribute *attr, char *buf)
602{
603 struct qeth_card *card = dev_get_drvdata(dev);
604
605 if (!card)
606 return -EINVAL;
607
608 return sprintf(buf, "%i\n", card->ipato.invert6? 1:0);
609}
610
611static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
612 struct device_attribute *attr, const char *buf, size_t count)
613{
614 struct qeth_card *card = dev_get_drvdata(dev);
615 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000616 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100617
618 if (!card)
619 return -EINVAL;
620
Frank Blaschkac4949f02010-05-11 19:34:47 +0000621 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100622 tmp = strsep((char **) &buf, "\n");
623 if (!strcmp(tmp, "toggle")) {
624 card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
625 } else if (!strcmp(tmp, "1")) {
626 card->ipato.invert6 = 1;
627 } else if (!strcmp(tmp, "0")) {
628 card->ipato.invert6 = 0;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000629 } else
630 rc = -EINVAL;
631 mutex_unlock(&card->conf_mutex);
632 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100633}
634
635static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
636 qeth_l3_dev_ipato_invert6_show,
637 qeth_l3_dev_ipato_invert6_store);
638
639
640static ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev,
641 struct device_attribute *attr, char *buf)
642{
643 struct qeth_card *card = dev_get_drvdata(dev);
644
645 if (!card)
646 return -EINVAL;
647
648 return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV6);
649}
650
651static ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev,
652 struct device_attribute *attr, const char *buf, size_t count)
653{
654 struct qeth_card *card = dev_get_drvdata(dev);
655
656 if (!card)
657 return -EINVAL;
658
659 return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6);
660}
661
662static QETH_DEVICE_ATTR(ipato_add6, add6, 0644,
663 qeth_l3_dev_ipato_add6_show,
664 qeth_l3_dev_ipato_add6_store);
665
666static ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev,
667 struct device_attribute *attr, const char *buf, size_t count)
668{
669 struct qeth_card *card = dev_get_drvdata(dev);
670
671 if (!card)
672 return -EINVAL;
673
674 return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6);
675}
676
677static QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL,
678 qeth_l3_dev_ipato_del6_store);
679
680static struct attribute *qeth_ipato_device_attrs[] = {
681 &dev_attr_ipato_enable.attr,
682 &dev_attr_ipato_invert4.attr,
683 &dev_attr_ipato_add4.attr,
684 &dev_attr_ipato_del4.attr,
685 &dev_attr_ipato_invert6.attr,
686 &dev_attr_ipato_add6.attr,
687 &dev_attr_ipato_del6.attr,
688 NULL,
689};
690
691static struct attribute_group qeth_device_ipato_group = {
692 .name = "ipa_takeover",
693 .attrs = qeth_ipato_device_attrs,
694};
695
696static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
697 enum qeth_prot_versions proto)
698{
699 struct qeth_ipaddr *ipaddr;
700 char addr_str[40];
701 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
702 unsigned long flags;
703 int i = 0;
704
705 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
706 entry_len += 2; /* \n + terminator */
707 spin_lock_irqsave(&card->ip_lock, flags);
708 list_for_each_entry(ipaddr, &card->ip_list, entry) {
709 if (ipaddr->proto != proto)
710 continue;
711 if (ipaddr->type != QETH_IP_TYPE_VIPA)
712 continue;
713 /* String must not be longer than PAGE_SIZE. So we check if
714 * string length gets near PAGE_SIZE. Then we can savely display
715 * the next IPv6 address (worst case, compared to IPv4) */
716 if ((PAGE_SIZE - i) <= entry_len)
717 break;
718 qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
719 addr_str);
720 i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
721 }
722 spin_unlock_irqrestore(&card->ip_lock, flags);
723 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
724
725 return i;
726}
727
728static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev,
729 struct device_attribute *attr, char *buf)
730{
731 struct qeth_card *card = dev_get_drvdata(dev);
732
733 if (!card)
734 return -EINVAL;
735
736 return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
737}
738
739static int qeth_l3_parse_vipae(const char *buf, enum qeth_prot_versions proto,
740 u8 *addr)
741{
742 if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100743 return -EINVAL;
744 }
745 return 0;
746}
747
748static ssize_t qeth_l3_dev_vipa_add_store(const char *buf, size_t count,
749 struct qeth_card *card, enum qeth_prot_versions proto)
750{
751 u8 addr[16] = {0, };
752 int rc;
753
Frank Blaschkac4949f02010-05-11 19:34:47 +0000754 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100755 rc = qeth_l3_parse_vipae(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000756 if (!rc)
757 rc = qeth_l3_add_vipa(card, proto, addr);
758 mutex_unlock(&card->conf_mutex);
759 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100760}
761
762static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev,
763 struct device_attribute *attr, const char *buf, size_t count)
764{
765 struct qeth_card *card = dev_get_drvdata(dev);
766
767 if (!card)
768 return -EINVAL;
769
770 return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV4);
771}
772
773static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
774 qeth_l3_dev_vipa_add4_show,
775 qeth_l3_dev_vipa_add4_store);
776
777static ssize_t qeth_l3_dev_vipa_del_store(const char *buf, size_t count,
778 struct qeth_card *card, enum qeth_prot_versions proto)
779{
780 u8 addr[16];
781 int rc;
782
Frank Blaschkac4949f02010-05-11 19:34:47 +0000783 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100784 rc = qeth_l3_parse_vipae(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000785 if (!rc)
786 qeth_l3_del_vipa(card, proto, addr);
787 mutex_unlock(&card->conf_mutex);
788 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100789}
790
791static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev,
792 struct device_attribute *attr, const char *buf, size_t count)
793{
794 struct qeth_card *card = dev_get_drvdata(dev);
795
796 if (!card)
797 return -EINVAL;
798
799 return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV4);
800}
801
802static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL,
803 qeth_l3_dev_vipa_del4_store);
804
805static ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev,
806 struct device_attribute *attr, char *buf)
807{
808 struct qeth_card *card = dev_get_drvdata(dev);
809
810 if (!card)
811 return -EINVAL;
812
813 return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV6);
814}
815
816static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev,
817 struct device_attribute *attr, const char *buf, size_t count)
818{
819 struct qeth_card *card = dev_get_drvdata(dev);
820
821 if (!card)
822 return -EINVAL;
823
824 return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV6);
825}
826
827static QETH_DEVICE_ATTR(vipa_add6, add6, 0644,
828 qeth_l3_dev_vipa_add6_show,
829 qeth_l3_dev_vipa_add6_store);
830
831static ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev,
832 struct device_attribute *attr, const char *buf, size_t count)
833{
834 struct qeth_card *card = dev_get_drvdata(dev);
835
836 if (!card)
837 return -EINVAL;
838
839 return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6);
840}
841
842static QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL,
843 qeth_l3_dev_vipa_del6_store);
844
845static struct attribute *qeth_vipa_device_attrs[] = {
846 &dev_attr_vipa_add4.attr,
847 &dev_attr_vipa_del4.attr,
848 &dev_attr_vipa_add6.attr,
849 &dev_attr_vipa_del6.attr,
850 NULL,
851};
852
853static struct attribute_group qeth_device_vipa_group = {
854 .name = "vipa",
855 .attrs = qeth_vipa_device_attrs,
856};
857
858static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
859 enum qeth_prot_versions proto)
860{
861 struct qeth_ipaddr *ipaddr;
862 char addr_str[40];
863 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
864 unsigned long flags;
865 int i = 0;
866
867 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
868 entry_len += 2; /* \n + terminator */
869 spin_lock_irqsave(&card->ip_lock, flags);
870 list_for_each_entry(ipaddr, &card->ip_list, entry) {
871 if (ipaddr->proto != proto)
872 continue;
873 if (ipaddr->type != QETH_IP_TYPE_RXIP)
874 continue;
875 /* String must not be longer than PAGE_SIZE. So we check if
876 * string length gets near PAGE_SIZE. Then we can savely display
877 * the next IPv6 address (worst case, compared to IPv4) */
878 if ((PAGE_SIZE - i) <= entry_len)
879 break;
880 qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
881 addr_str);
882 i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
883 }
884 spin_unlock_irqrestore(&card->ip_lock, flags);
885 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
886
887 return i;
888}
889
890static ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev,
891 struct device_attribute *attr, char *buf)
892{
893 struct qeth_card *card = dev_get_drvdata(dev);
894
895 if (!card)
896 return -EINVAL;
897
898 return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
899}
900
901static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto,
902 u8 *addr)
903{
904 if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100905 return -EINVAL;
906 }
907 return 0;
908}
909
910static ssize_t qeth_l3_dev_rxip_add_store(const char *buf, size_t count,
911 struct qeth_card *card, enum qeth_prot_versions proto)
912{
913 u8 addr[16] = {0, };
914 int rc;
915
Frank Blaschkac4949f02010-05-11 19:34:47 +0000916 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100917 rc = qeth_l3_parse_rxipe(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000918 if (!rc)
919 rc = qeth_l3_add_rxip(card, proto, addr);
920 mutex_unlock(&card->conf_mutex);
921 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100922}
923
924static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev,
925 struct device_attribute *attr, const char *buf, size_t count)
926{
927 struct qeth_card *card = dev_get_drvdata(dev);
928
929 if (!card)
930 return -EINVAL;
931
932 return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV4);
933}
934
935static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
936 qeth_l3_dev_rxip_add4_show,
937 qeth_l3_dev_rxip_add4_store);
938
939static ssize_t qeth_l3_dev_rxip_del_store(const char *buf, size_t count,
940 struct qeth_card *card, enum qeth_prot_versions proto)
941{
942 u8 addr[16];
943 int rc;
944
Frank Blaschkac4949f02010-05-11 19:34:47 +0000945 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100946 rc = qeth_l3_parse_rxipe(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000947 if (!rc)
948 qeth_l3_del_rxip(card, proto, addr);
949 mutex_unlock(&card->conf_mutex);
950 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100951}
952
953static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev,
954 struct device_attribute *attr, const char *buf, size_t count)
955{
956 struct qeth_card *card = dev_get_drvdata(dev);
957
958 if (!card)
959 return -EINVAL;
960
961 return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV4);
962}
963
964static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL,
965 qeth_l3_dev_rxip_del4_store);
966
967static ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev,
968 struct device_attribute *attr, char *buf)
969{
970 struct qeth_card *card = dev_get_drvdata(dev);
971
972 if (!card)
973 return -EINVAL;
974
975 return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV6);
976}
977
978static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev,
979 struct device_attribute *attr, const char *buf, size_t count)
980{
981 struct qeth_card *card = dev_get_drvdata(dev);
982
983 if (!card)
984 return -EINVAL;
985
986 return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV6);
987}
988
989static QETH_DEVICE_ATTR(rxip_add6, add6, 0644,
990 qeth_l3_dev_rxip_add6_show,
991 qeth_l3_dev_rxip_add6_store);
992
993static ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev,
994 struct device_attribute *attr, const char *buf, size_t count)
995{
996 struct qeth_card *card = dev_get_drvdata(dev);
997
998 if (!card)
999 return -EINVAL;
1000
1001 return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV6);
1002}
1003
1004static QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL,
1005 qeth_l3_dev_rxip_del6_store);
1006
1007static struct attribute *qeth_rxip_device_attrs[] = {
1008 &dev_attr_rxip_add4.attr,
1009 &dev_attr_rxip_del4.attr,
1010 &dev_attr_rxip_add6.attr,
1011 &dev_attr_rxip_del6.attr,
1012 NULL,
1013};
1014
1015static struct attribute_group qeth_device_rxip_group = {
1016 .name = "rxip",
1017 .attrs = qeth_rxip_device_attrs,
1018};
1019
1020int qeth_l3_create_device_attributes(struct device *dev)
1021{
1022 int ret;
1023
1024 ret = sysfs_create_group(&dev->kobj, &qeth_l3_device_attr_group);
1025 if (ret)
1026 return ret;
1027
1028 ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group);
1029 if (ret) {
1030 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1031 return ret;
1032 }
1033
1034 ret = sysfs_create_group(&dev->kobj, &qeth_device_vipa_group);
1035 if (ret) {
1036 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1037 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1038 return ret;
1039 }
1040
1041 ret = sysfs_create_group(&dev->kobj, &qeth_device_rxip_group);
1042 if (ret) {
1043 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1044 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1045 sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
1046 return ret;
1047 }
1048 return 0;
1049}
1050
1051void qeth_l3_remove_device_attributes(struct device *dev)
1052{
1053 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1054 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1055 sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
1056 sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
1057}