blob: 3f08b11274aeede53cffa6822738ebd4f5ed1396 [file] [log] [blame]
Frank Blaschka4a71df52008-02-15 09:19:42 +01001/*
2 * drivers/s390/net/qeth_l3_sys.c
3 *
4 * Copyright IBM Corp. 2007
5 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
6 * Frank Pavlic <fpavlic@de.ibm.com>,
7 * Thomas Spatzier <tspat@de.ibm.com>,
8 * Frank Blaschka <frank.blaschka@de.ibm.com>
9 */
10
11#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
16static const char *qeth_l3_get_checksum_str(struct qeth_card *card)
17{
18 if (card->options.checksum_type == SW_CHECKSUMMING)
19 return "sw";
20 else if (card->options.checksum_type == HW_CHECKSUMMING)
21 return "hw";
22 else
23 return "no";
24}
25
26static ssize_t qeth_l3_dev_route_show(struct qeth_card *card,
27 struct qeth_routing_info *route, char *buf)
28{
29 switch (route->type) {
30 case PRIMARY_ROUTER:
31 return sprintf(buf, "%s\n", "primary router");
32 case SECONDARY_ROUTER:
33 return sprintf(buf, "%s\n", "secondary router");
34 case MULTICAST_ROUTER:
35 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
36 return sprintf(buf, "%s\n", "multicast router+");
37 else
38 return sprintf(buf, "%s\n", "multicast router");
39 case PRIMARY_CONNECTOR:
40 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
41 return sprintf(buf, "%s\n", "primary connector+");
42 else
43 return sprintf(buf, "%s\n", "primary connector");
44 case SECONDARY_CONNECTOR:
45 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
46 return sprintf(buf, "%s\n", "secondary connector+");
47 else
48 return sprintf(buf, "%s\n", "secondary connector");
49 default:
50 return sprintf(buf, "%s\n", "no");
51 }
52}
53
54static ssize_t qeth_l3_dev_route4_show(struct device *dev,
55 struct device_attribute *attr, char *buf)
56{
57 struct qeth_card *card = dev_get_drvdata(dev);
58
59 if (!card)
60 return -EINVAL;
61
62 return qeth_l3_dev_route_show(card, &card->options.route4, buf);
63}
64
65static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
66 struct qeth_routing_info *route, enum qeth_prot_versions prot,
67 const char *buf, size_t count)
68{
69 enum qeth_routing_types old_route_type = route->type;
70 char *tmp;
71 int rc;
72
73 tmp = strsep((char **) &buf, "\n");
74
75 if (!strcmp(tmp, "no_router")) {
76 route->type = NO_ROUTER;
77 } else if (!strcmp(tmp, "primary_connector")) {
78 route->type = PRIMARY_CONNECTOR;
79 } else if (!strcmp(tmp, "secondary_connector")) {
80 route->type = SECONDARY_CONNECTOR;
81 } else if (!strcmp(tmp, "primary_router")) {
82 route->type = PRIMARY_ROUTER;
83 } else if (!strcmp(tmp, "secondary_router")) {
84 route->type = SECONDARY_ROUTER;
85 } else if (!strcmp(tmp, "multicast_router")) {
86 route->type = MULTICAST_ROUTER;
87 } else {
Frank Blaschka4a71df52008-02-15 09:19:42 +010088 return -EINVAL;
89 }
90 if (((card->state == CARD_STATE_SOFTSETUP) ||
91 (card->state == CARD_STATE_UP)) &&
92 (old_route_type != route->type)) {
93 if (prot == QETH_PROT_IPV4)
94 rc = qeth_l3_setrouting_v4(card);
95 else if (prot == QETH_PROT_IPV6)
96 rc = qeth_l3_setrouting_v6(card);
97 }
98 return count;
99}
100
101static ssize_t qeth_l3_dev_route4_store(struct device *dev,
102 struct device_attribute *attr, const char *buf, size_t count)
103{
104 struct qeth_card *card = dev_get_drvdata(dev);
105
106 if (!card)
107 return -EINVAL;
108
109 return qeth_l3_dev_route_store(card, &card->options.route4,
110 QETH_PROT_IPV4, buf, count);
111}
112
113static DEVICE_ATTR(route4, 0644, qeth_l3_dev_route4_show,
114 qeth_l3_dev_route4_store);
115
116static ssize_t qeth_l3_dev_route6_show(struct device *dev,
117 struct device_attribute *attr, char *buf)
118{
119 struct qeth_card *card = dev_get_drvdata(dev);
120
121 if (!card)
122 return -EINVAL;
123
Frank Blaschka4a71df52008-02-15 09:19:42 +0100124 return qeth_l3_dev_route_show(card, &card->options.route6, buf);
125}
126
127static ssize_t qeth_l3_dev_route6_store(struct device *dev,
128 struct device_attribute *attr, const char *buf, size_t count)
129{
130 struct qeth_card *card = dev_get_drvdata(dev);
131
132 if (!card)
133 return -EINVAL;
134
Frank Blaschka4a71df52008-02-15 09:19:42 +0100135 return qeth_l3_dev_route_store(card, &card->options.route6,
136 QETH_PROT_IPV6, buf, count);
137}
138
139static DEVICE_ATTR(route6, 0644, qeth_l3_dev_route6_show,
140 qeth_l3_dev_route6_store);
141
142static ssize_t qeth_l3_dev_fake_broadcast_show(struct device *dev,
143 struct device_attribute *attr, char *buf)
144{
145 struct qeth_card *card = dev_get_drvdata(dev);
146
147 if (!card)
148 return -EINVAL;
149
150 return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0);
151}
152
153static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev,
154 struct device_attribute *attr, const char *buf, size_t count)
155{
156 struct qeth_card *card = dev_get_drvdata(dev);
157 char *tmp;
158 int i;
159
160 if (!card)
161 return -EINVAL;
162
163 if ((card->state != CARD_STATE_DOWN) &&
164 (card->state != CARD_STATE_RECOVER))
165 return -EPERM;
166
167 i = simple_strtoul(buf, &tmp, 16);
168 if ((i == 0) || (i == 1))
169 card->options.fake_broadcast = i;
170 else {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100171 return -EINVAL;
172 }
173 return count;
174}
175
176static DEVICE_ATTR(fake_broadcast, 0644, qeth_l3_dev_fake_broadcast_show,
177 qeth_l3_dev_fake_broadcast_store);
178
179static ssize_t qeth_l3_dev_broadcast_mode_show(struct device *dev,
180 struct device_attribute *attr, char *buf)
181{
182 struct qeth_card *card = dev_get_drvdata(dev);
183
184 if (!card)
185 return -EINVAL;
186
187 if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
188 (card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
189 return sprintf(buf, "n/a\n");
190
191 return sprintf(buf, "%s\n", (card->options.broadcast_mode ==
192 QETH_TR_BROADCAST_ALLRINGS)?
193 "all rings":"local");
194}
195
196static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev,
197 struct device_attribute *attr, const char *buf, size_t count)
198{
199 struct qeth_card *card = dev_get_drvdata(dev);
200 char *tmp;
201
202 if (!card)
203 return -EINVAL;
204
205 if ((card->state != CARD_STATE_DOWN) &&
206 (card->state != CARD_STATE_RECOVER))
207 return -EPERM;
208
209 if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
210 (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100211 return -EINVAL;
212 }
213
214 tmp = strsep((char **) &buf, "\n");
215
216 if (!strcmp(tmp, "local")) {
217 card->options.broadcast_mode = QETH_TR_BROADCAST_LOCAL;
218 return count;
219 } else if (!strcmp(tmp, "all_rings")) {
220 card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
221 return count;
222 } else {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100223 return -EINVAL;
224 }
225 return count;
226}
227
228static DEVICE_ATTR(broadcast_mode, 0644, qeth_l3_dev_broadcast_mode_show,
229 qeth_l3_dev_broadcast_mode_store);
230
231static ssize_t qeth_l3_dev_canonical_macaddr_show(struct device *dev,
232 struct device_attribute *attr, char *buf)
233{
234 struct qeth_card *card = dev_get_drvdata(dev);
235
236 if (!card)
237 return -EINVAL;
238
239 if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
240 (card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
241 return sprintf(buf, "n/a\n");
242
243 return sprintf(buf, "%i\n", (card->options.macaddr_mode ==
244 QETH_TR_MACADDR_CANONICAL)? 1:0);
245}
246
247static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev,
248 struct device_attribute *attr, const char *buf, size_t count)
249{
250 struct qeth_card *card = dev_get_drvdata(dev);
251 char *tmp;
252 int i;
253
254 if (!card)
255 return -EINVAL;
256
257 if ((card->state != CARD_STATE_DOWN) &&
258 (card->state != CARD_STATE_RECOVER))
259 return -EPERM;
260
261 if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
262 (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100263 return -EINVAL;
264 }
265
266 i = simple_strtoul(buf, &tmp, 16);
267 if ((i == 0) || (i == 1))
268 card->options.macaddr_mode = i?
269 QETH_TR_MACADDR_CANONICAL :
270 QETH_TR_MACADDR_NONCANONICAL;
271 else {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100272 return -EINVAL;
273 }
274 return count;
275}
276
277static DEVICE_ATTR(canonical_macaddr, 0644, qeth_l3_dev_canonical_macaddr_show,
278 qeth_l3_dev_canonical_macaddr_store);
279
280static ssize_t qeth_l3_dev_checksum_show(struct device *dev,
281 struct device_attribute *attr, char *buf)
282{
283 struct qeth_card *card = dev_get_drvdata(dev);
284
285 if (!card)
286 return -EINVAL;
287
288 return sprintf(buf, "%s checksumming\n",
289 qeth_l3_get_checksum_str(card));
290}
291
292static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
293 struct device_attribute *attr, const char *buf, size_t count)
294{
295 struct qeth_card *card = dev_get_drvdata(dev);
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000296 enum qeth_checksum_types csum_type;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100297 char *tmp;
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000298 int rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100299
300 if (!card)
301 return -EINVAL;
302
Frank Blaschka4a71df52008-02-15 09:19:42 +0100303 tmp = strsep((char **) &buf, "\n");
304 if (!strcmp(tmp, "sw_checksumming"))
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000305 csum_type = SW_CHECKSUMMING;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100306 else if (!strcmp(tmp, "hw_checksumming"))
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000307 csum_type = HW_CHECKSUMMING;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100308 else if (!strcmp(tmp, "no_checksumming"))
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000309 csum_type = NO_CHECKSUMMING;
310 else
Frank Blaschka4a71df52008-02-15 09:19:42 +0100311 return -EINVAL;
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000312
313 rc = qeth_l3_set_rx_csum(card, csum_type);
314 if (rc)
315 return rc;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100316 return count;
317}
318
319static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show,
320 qeth_l3_dev_checksum_store);
321
Ursula Braun76b11f82010-01-11 02:50:50 +0000322static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
323 struct device_attribute *attr, char *buf)
324{
325 struct qeth_card *card = dev_get_drvdata(dev);
326
327 if (!card)
328 return -EINVAL;
329
330 return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
331}
332
333static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
334 struct device_attribute *attr, const char *buf, size_t count)
335{
336 struct qeth_card *card = dev_get_drvdata(dev);
337 int ret;
338 unsigned long i;
339
340 if (!card)
341 return -EINVAL;
342
343 if (card->info.type != QETH_CARD_TYPE_IQD)
344 return -EPERM;
345
346 if ((card->state != CARD_STATE_DOWN) &&
347 (card->state != CARD_STATE_RECOVER))
348 return -EPERM;
349
350 ret = strict_strtoul(buf, 16, &i);
351 if (ret)
352 return -EINVAL;
353 switch (i) {
354 case 0:
355 card->options.sniffer = i;
356 break;
357 case 1:
358 ret = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
359 if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) {
360 card->options.sniffer = i;
361 if (card->qdio.init_pool.buf_count !=
362 QETH_IN_BUF_COUNT_MAX)
363 qeth_realloc_buffer_pool(card,
364 QETH_IN_BUF_COUNT_MAX);
365 break;
366 } else
367 return -EPERM;
368 default: /* fall through */
369 return -EINVAL;
370 }
371 return count;
372}
373
374static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
375 qeth_l3_dev_sniffer_store);
376
Frank Blaschkac3b4a742009-11-12 00:11:44 +0000377static ssize_t qeth_l3_dev_large_send_show(struct device *dev,
378 struct device_attribute *attr, char *buf)
379{
380 struct qeth_card *card = dev_get_drvdata(dev);
381
382 if (!card)
383 return -EINVAL;
384
385 switch (card->options.large_send) {
386 case QETH_LARGE_SEND_NO:
387 return sprintf(buf, "%s\n", "no");
388 case QETH_LARGE_SEND_TSO:
389 return sprintf(buf, "%s\n", "TSO");
390 default:
391 return sprintf(buf, "%s\n", "N/A");
392 }
393}
394
395static ssize_t qeth_l3_dev_large_send_store(struct device *dev,
396 struct device_attribute *attr, const char *buf, size_t count)
397{
398 struct qeth_card *card = dev_get_drvdata(dev);
399 enum qeth_large_send_types type;
400 int rc = 0;
401 char *tmp;
402
403 if (!card)
404 return -EINVAL;
405 tmp = strsep((char **) &buf, "\n");
406 if (!strcmp(tmp, "no"))
407 type = QETH_LARGE_SEND_NO;
408 else if (!strcmp(tmp, "TSO"))
409 type = QETH_LARGE_SEND_TSO;
410 else
411 return -EINVAL;
412
413 if (card->options.large_send == type)
414 return count;
415 rc = qeth_l3_set_large_send(card, type);
416 if (rc)
417 return rc;
418 return count;
419}
420
421static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show,
422 qeth_l3_dev_large_send_store);
423
Frank Blaschka4a71df52008-02-15 09:19:42 +0100424static struct attribute *qeth_l3_device_attrs[] = {
425 &dev_attr_route4.attr,
426 &dev_attr_route6.attr,
427 &dev_attr_fake_broadcast.attr,
428 &dev_attr_broadcast_mode.attr,
429 &dev_attr_canonical_macaddr.attr,
430 &dev_attr_checksumming.attr,
Ursula Braun76b11f82010-01-11 02:50:50 +0000431 &dev_attr_sniffer.attr,
Frank Blaschkac3b4a742009-11-12 00:11:44 +0000432 &dev_attr_large_send.attr,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100433 NULL,
434};
435
436static struct attribute_group qeth_l3_device_attr_group = {
437 .attrs = qeth_l3_device_attrs,
438};
439
440static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev,
441 struct device_attribute *attr, char *buf)
442{
443 struct qeth_card *card = dev_get_drvdata(dev);
444
445 if (!card)
446 return -EINVAL;
447
448 return sprintf(buf, "%i\n", card->ipato.enabled? 1:0);
449}
450
451static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
452 struct device_attribute *attr, const char *buf, size_t count)
453{
454 struct qeth_card *card = dev_get_drvdata(dev);
455 char *tmp;
456
457 if (!card)
458 return -EINVAL;
459
460 if ((card->state != CARD_STATE_DOWN) &&
461 (card->state != CARD_STATE_RECOVER))
462 return -EPERM;
463
464 tmp = strsep((char **) &buf, "\n");
465 if (!strcmp(tmp, "toggle")) {
466 card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
467 } else if (!strcmp(tmp, "1")) {
468 card->ipato.enabled = 1;
469 } else if (!strcmp(tmp, "0")) {
470 card->ipato.enabled = 0;
471 } else {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100472 return -EINVAL;
473 }
474 return count;
475}
476
477static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
478 qeth_l3_dev_ipato_enable_show,
479 qeth_l3_dev_ipato_enable_store);
480
481static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev,
482 struct device_attribute *attr, char *buf)
483{
484 struct qeth_card *card = dev_get_drvdata(dev);
485
486 if (!card)
487 return -EINVAL;
488
489 return sprintf(buf, "%i\n", card->ipato.invert4? 1:0);
490}
491
492static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
493 struct device_attribute *attr,
494 const char *buf, size_t count)
495{
496 struct qeth_card *card = dev_get_drvdata(dev);
497 char *tmp;
498
499 if (!card)
500 return -EINVAL;
501
502 tmp = strsep((char **) &buf, "\n");
503 if (!strcmp(tmp, "toggle")) {
504 card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
505 } else if (!strcmp(tmp, "1")) {
506 card->ipato.invert4 = 1;
507 } else if (!strcmp(tmp, "0")) {
508 card->ipato.invert4 = 0;
509 } else {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100510 return -EINVAL;
511 }
512 return count;
513}
514
515static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
516 qeth_l3_dev_ipato_invert4_show,
517 qeth_l3_dev_ipato_invert4_store);
518
519static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
520 enum qeth_prot_versions proto)
521{
522 struct qeth_ipato_entry *ipatoe;
523 unsigned long flags;
524 char addr_str[40];
525 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
526 int i = 0;
527
528 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
529 /* add strlen for "/<mask>\n" */
530 entry_len += (proto == QETH_PROT_IPV4)? 5 : 6;
531 spin_lock_irqsave(&card->ip_lock, flags);
532 list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
533 if (ipatoe->proto != proto)
534 continue;
535 /* String must not be longer than PAGE_SIZE. So we check if
536 * string length gets near PAGE_SIZE. Then we can savely display
537 * the next IPv6 address (worst case, compared to IPv4) */
538 if ((PAGE_SIZE - i) <= entry_len)
539 break;
540 qeth_l3_ipaddr_to_string(proto, ipatoe->addr, addr_str);
541 i += snprintf(buf + i, PAGE_SIZE - i,
542 "%s/%i\n", addr_str, ipatoe->mask_bits);
543 }
544 spin_unlock_irqrestore(&card->ip_lock, flags);
545 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
546
547 return i;
548}
549
550static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev,
551 struct device_attribute *attr, char *buf)
552{
553 struct qeth_card *card = dev_get_drvdata(dev);
554
555 if (!card)
556 return -EINVAL;
557
558 return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
559}
560
561static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto,
562 u8 *addr, int *mask_bits)
563{
564 const char *start, *end;
565 char *tmp;
566 char buffer[40] = {0, };
567
568 start = buf;
569 /* get address string */
570 end = strchr(start, '/');
571 if (!end || (end - start >= 40)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100572 return -EINVAL;
573 }
574 strncpy(buffer, start, end - start);
575 if (qeth_l3_string_to_ipaddr(buffer, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100576 return -EINVAL;
577 }
578 start = end + 1;
579 *mask_bits = simple_strtoul(start, &tmp, 10);
580 if (!strlen(start) ||
581 (tmp == start) ||
582 (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100583 return -EINVAL;
584 }
585 return 0;
586}
587
588static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count,
589 struct qeth_card *card, enum qeth_prot_versions proto)
590{
591 struct qeth_ipato_entry *ipatoe;
592 u8 addr[16];
593 int mask_bits;
594 int rc;
595
596 rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
597 if (rc)
598 return rc;
599
600 ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL);
601 if (!ipatoe) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100602 return -ENOMEM;
603 }
604 ipatoe->proto = proto;
605 memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4)? 4:16);
606 ipatoe->mask_bits = mask_bits;
607
608 rc = qeth_l3_add_ipato_entry(card, ipatoe);
609 if (rc) {
610 kfree(ipatoe);
611 return rc;
612 }
613
614 return count;
615}
616
617static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev,
618 struct device_attribute *attr, const char *buf, size_t count)
619{
620 struct qeth_card *card = dev_get_drvdata(dev);
621
622 if (!card)
623 return -EINVAL;
624
625 return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4);
626}
627
628static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
629 qeth_l3_dev_ipato_add4_show,
630 qeth_l3_dev_ipato_add4_store);
631
632static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
633 struct qeth_card *card, enum qeth_prot_versions proto)
634{
635 u8 addr[16];
636 int mask_bits;
637 int rc;
638
639 rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
640 if (rc)
641 return rc;
642
643 qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
644
645 return count;
646}
647
648static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev,
649 struct device_attribute *attr, const char *buf, size_t count)
650{
651 struct qeth_card *card = dev_get_drvdata(dev);
652
653 if (!card)
654 return -EINVAL;
655
656 return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4);
657}
658
659static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL,
660 qeth_l3_dev_ipato_del4_store);
661
662static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev,
663 struct device_attribute *attr, char *buf)
664{
665 struct qeth_card *card = dev_get_drvdata(dev);
666
667 if (!card)
668 return -EINVAL;
669
670 return sprintf(buf, "%i\n", card->ipato.invert6? 1:0);
671}
672
673static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
674 struct device_attribute *attr, const char *buf, size_t count)
675{
676 struct qeth_card *card = dev_get_drvdata(dev);
677 char *tmp;
678
679 if (!card)
680 return -EINVAL;
681
682 tmp = strsep((char **) &buf, "\n");
683 if (!strcmp(tmp, "toggle")) {
684 card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
685 } else if (!strcmp(tmp, "1")) {
686 card->ipato.invert6 = 1;
687 } else if (!strcmp(tmp, "0")) {
688 card->ipato.invert6 = 0;
689 } else {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100690 return -EINVAL;
691 }
692 return count;
693}
694
695static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
696 qeth_l3_dev_ipato_invert6_show,
697 qeth_l3_dev_ipato_invert6_store);
698
699
700static ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev,
701 struct device_attribute *attr, char *buf)
702{
703 struct qeth_card *card = dev_get_drvdata(dev);
704
705 if (!card)
706 return -EINVAL;
707
708 return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV6);
709}
710
711static ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev,
712 struct device_attribute *attr, const char *buf, size_t count)
713{
714 struct qeth_card *card = dev_get_drvdata(dev);
715
716 if (!card)
717 return -EINVAL;
718
719 return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6);
720}
721
722static QETH_DEVICE_ATTR(ipato_add6, add6, 0644,
723 qeth_l3_dev_ipato_add6_show,
724 qeth_l3_dev_ipato_add6_store);
725
726static ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev,
727 struct device_attribute *attr, const char *buf, size_t count)
728{
729 struct qeth_card *card = dev_get_drvdata(dev);
730
731 if (!card)
732 return -EINVAL;
733
734 return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6);
735}
736
737static QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL,
738 qeth_l3_dev_ipato_del6_store);
739
740static struct attribute *qeth_ipato_device_attrs[] = {
741 &dev_attr_ipato_enable.attr,
742 &dev_attr_ipato_invert4.attr,
743 &dev_attr_ipato_add4.attr,
744 &dev_attr_ipato_del4.attr,
745 &dev_attr_ipato_invert6.attr,
746 &dev_attr_ipato_add6.attr,
747 &dev_attr_ipato_del6.attr,
748 NULL,
749};
750
751static struct attribute_group qeth_device_ipato_group = {
752 .name = "ipa_takeover",
753 .attrs = qeth_ipato_device_attrs,
754};
755
756static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
757 enum qeth_prot_versions proto)
758{
759 struct qeth_ipaddr *ipaddr;
760 char addr_str[40];
761 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
762 unsigned long flags;
763 int i = 0;
764
765 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
766 entry_len += 2; /* \n + terminator */
767 spin_lock_irqsave(&card->ip_lock, flags);
768 list_for_each_entry(ipaddr, &card->ip_list, entry) {
769 if (ipaddr->proto != proto)
770 continue;
771 if (ipaddr->type != QETH_IP_TYPE_VIPA)
772 continue;
773 /* String must not be longer than PAGE_SIZE. So we check if
774 * string length gets near PAGE_SIZE. Then we can savely display
775 * the next IPv6 address (worst case, compared to IPv4) */
776 if ((PAGE_SIZE - i) <= entry_len)
777 break;
778 qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
779 addr_str);
780 i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
781 }
782 spin_unlock_irqrestore(&card->ip_lock, flags);
783 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
784
785 return i;
786}
787
788static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev,
789 struct device_attribute *attr, char *buf)
790{
791 struct qeth_card *card = dev_get_drvdata(dev);
792
793 if (!card)
794 return -EINVAL;
795
796 return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
797}
798
799static int qeth_l3_parse_vipae(const char *buf, enum qeth_prot_versions proto,
800 u8 *addr)
801{
802 if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100803 return -EINVAL;
804 }
805 return 0;
806}
807
808static ssize_t qeth_l3_dev_vipa_add_store(const char *buf, size_t count,
809 struct qeth_card *card, enum qeth_prot_versions proto)
810{
811 u8 addr[16] = {0, };
812 int rc;
813
814 rc = qeth_l3_parse_vipae(buf, proto, addr);
815 if (rc)
816 return rc;
817
818 rc = qeth_l3_add_vipa(card, proto, addr);
819 if (rc)
820 return rc;
821
822 return count;
823}
824
825static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev,
826 struct device_attribute *attr, const char *buf, size_t count)
827{
828 struct qeth_card *card = dev_get_drvdata(dev);
829
830 if (!card)
831 return -EINVAL;
832
833 return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV4);
834}
835
836static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
837 qeth_l3_dev_vipa_add4_show,
838 qeth_l3_dev_vipa_add4_store);
839
840static ssize_t qeth_l3_dev_vipa_del_store(const char *buf, size_t count,
841 struct qeth_card *card, enum qeth_prot_versions proto)
842{
843 u8 addr[16];
844 int rc;
845
846 rc = qeth_l3_parse_vipae(buf, proto, addr);
847 if (rc)
848 return rc;
849
850 qeth_l3_del_vipa(card, proto, addr);
851
852 return count;
853}
854
855static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev,
856 struct device_attribute *attr, const char *buf, size_t count)
857{
858 struct qeth_card *card = dev_get_drvdata(dev);
859
860 if (!card)
861 return -EINVAL;
862
863 return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV4);
864}
865
866static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL,
867 qeth_l3_dev_vipa_del4_store);
868
869static ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev,
870 struct device_attribute *attr, char *buf)
871{
872 struct qeth_card *card = dev_get_drvdata(dev);
873
874 if (!card)
875 return -EINVAL;
876
877 return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV6);
878}
879
880static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev,
881 struct device_attribute *attr, const char *buf, size_t count)
882{
883 struct qeth_card *card = dev_get_drvdata(dev);
884
885 if (!card)
886 return -EINVAL;
887
888 return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV6);
889}
890
891static QETH_DEVICE_ATTR(vipa_add6, add6, 0644,
892 qeth_l3_dev_vipa_add6_show,
893 qeth_l3_dev_vipa_add6_store);
894
895static ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev,
896 struct device_attribute *attr, const char *buf, size_t count)
897{
898 struct qeth_card *card = dev_get_drvdata(dev);
899
900 if (!card)
901 return -EINVAL;
902
903 return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6);
904}
905
906static QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL,
907 qeth_l3_dev_vipa_del6_store);
908
909static struct attribute *qeth_vipa_device_attrs[] = {
910 &dev_attr_vipa_add4.attr,
911 &dev_attr_vipa_del4.attr,
912 &dev_attr_vipa_add6.attr,
913 &dev_attr_vipa_del6.attr,
914 NULL,
915};
916
917static struct attribute_group qeth_device_vipa_group = {
918 .name = "vipa",
919 .attrs = qeth_vipa_device_attrs,
920};
921
922static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
923 enum qeth_prot_versions proto)
924{
925 struct qeth_ipaddr *ipaddr;
926 char addr_str[40];
927 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
928 unsigned long flags;
929 int i = 0;
930
931 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
932 entry_len += 2; /* \n + terminator */
933 spin_lock_irqsave(&card->ip_lock, flags);
934 list_for_each_entry(ipaddr, &card->ip_list, entry) {
935 if (ipaddr->proto != proto)
936 continue;
937 if (ipaddr->type != QETH_IP_TYPE_RXIP)
938 continue;
939 /* String must not be longer than PAGE_SIZE. So we check if
940 * string length gets near PAGE_SIZE. Then we can savely display
941 * the next IPv6 address (worst case, compared to IPv4) */
942 if ((PAGE_SIZE - i) <= entry_len)
943 break;
944 qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
945 addr_str);
946 i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
947 }
948 spin_unlock_irqrestore(&card->ip_lock, flags);
949 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
950
951 return i;
952}
953
954static ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev,
955 struct device_attribute *attr, char *buf)
956{
957 struct qeth_card *card = dev_get_drvdata(dev);
958
959 if (!card)
960 return -EINVAL;
961
962 return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
963}
964
965static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto,
966 u8 *addr)
967{
968 if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100969 return -EINVAL;
970 }
971 return 0;
972}
973
974static ssize_t qeth_l3_dev_rxip_add_store(const char *buf, size_t count,
975 struct qeth_card *card, enum qeth_prot_versions proto)
976{
977 u8 addr[16] = {0, };
978 int rc;
979
980 rc = qeth_l3_parse_rxipe(buf, proto, addr);
981 if (rc)
982 return rc;
983
984 rc = qeth_l3_add_rxip(card, proto, addr);
985 if (rc)
986 return rc;
987
988 return count;
989}
990
991static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev,
992 struct device_attribute *attr, const char *buf, size_t count)
993{
994 struct qeth_card *card = dev_get_drvdata(dev);
995
996 if (!card)
997 return -EINVAL;
998
999 return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV4);
1000}
1001
1002static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
1003 qeth_l3_dev_rxip_add4_show,
1004 qeth_l3_dev_rxip_add4_store);
1005
1006static ssize_t qeth_l3_dev_rxip_del_store(const char *buf, size_t count,
1007 struct qeth_card *card, enum qeth_prot_versions proto)
1008{
1009 u8 addr[16];
1010 int rc;
1011
1012 rc = qeth_l3_parse_rxipe(buf, proto, addr);
1013 if (rc)
1014 return rc;
1015
1016 qeth_l3_del_rxip(card, proto, addr);
1017
1018 return count;
1019}
1020
1021static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev,
1022 struct device_attribute *attr, const char *buf, size_t count)
1023{
1024 struct qeth_card *card = dev_get_drvdata(dev);
1025
1026 if (!card)
1027 return -EINVAL;
1028
1029 return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV4);
1030}
1031
1032static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL,
1033 qeth_l3_dev_rxip_del4_store);
1034
1035static ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev,
1036 struct device_attribute *attr, char *buf)
1037{
1038 struct qeth_card *card = dev_get_drvdata(dev);
1039
1040 if (!card)
1041 return -EINVAL;
1042
1043 return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV6);
1044}
1045
1046static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev,
1047 struct device_attribute *attr, const char *buf, size_t count)
1048{
1049 struct qeth_card *card = dev_get_drvdata(dev);
1050
1051 if (!card)
1052 return -EINVAL;
1053
1054 return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV6);
1055}
1056
1057static QETH_DEVICE_ATTR(rxip_add6, add6, 0644,
1058 qeth_l3_dev_rxip_add6_show,
1059 qeth_l3_dev_rxip_add6_store);
1060
1061static ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev,
1062 struct device_attribute *attr, const char *buf, size_t count)
1063{
1064 struct qeth_card *card = dev_get_drvdata(dev);
1065
1066 if (!card)
1067 return -EINVAL;
1068
1069 return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV6);
1070}
1071
1072static QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL,
1073 qeth_l3_dev_rxip_del6_store);
1074
1075static struct attribute *qeth_rxip_device_attrs[] = {
1076 &dev_attr_rxip_add4.attr,
1077 &dev_attr_rxip_del4.attr,
1078 &dev_attr_rxip_add6.attr,
1079 &dev_attr_rxip_del6.attr,
1080 NULL,
1081};
1082
1083static struct attribute_group qeth_device_rxip_group = {
1084 .name = "rxip",
1085 .attrs = qeth_rxip_device_attrs,
1086};
1087
1088int qeth_l3_create_device_attributes(struct device *dev)
1089{
1090 int ret;
1091
1092 ret = sysfs_create_group(&dev->kobj, &qeth_l3_device_attr_group);
1093 if (ret)
1094 return ret;
1095
1096 ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group);
1097 if (ret) {
1098 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1099 return ret;
1100 }
1101
1102 ret = sysfs_create_group(&dev->kobj, &qeth_device_vipa_group);
1103 if (ret) {
1104 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1105 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1106 return ret;
1107 }
1108
1109 ret = sysfs_create_group(&dev->kobj, &qeth_device_rxip_group);
1110 if (ret) {
1111 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1112 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1113 sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
1114 return ret;
1115 }
1116 return 0;
1117}
1118
1119void qeth_l3_remove_device_attributes(struct device *dev)
1120{
1121 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1122 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1123 sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
1124 sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
1125}