blob: 67cfa68dcf1b9781f45314521f357380a5a6568c [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
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
12
Frank Blaschka4a71df52008-02-15 09:19:42 +010013#include "qeth_l3.h"
14
15#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
16struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
17
18static const char *qeth_l3_get_checksum_str(struct qeth_card *card)
19{
20 if (card->options.checksum_type == SW_CHECKSUMMING)
21 return "sw";
22 else if (card->options.checksum_type == HW_CHECKSUMMING)
23 return "hw";
24 else
25 return "no";
26}
27
28static ssize_t qeth_l3_dev_route_show(struct qeth_card *card,
29 struct qeth_routing_info *route, char *buf)
30{
31 switch (route->type) {
32 case PRIMARY_ROUTER:
33 return sprintf(buf, "%s\n", "primary router");
34 case SECONDARY_ROUTER:
35 return sprintf(buf, "%s\n", "secondary router");
36 case MULTICAST_ROUTER:
37 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
38 return sprintf(buf, "%s\n", "multicast router+");
39 else
40 return sprintf(buf, "%s\n", "multicast router");
41 case PRIMARY_CONNECTOR:
42 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
43 return sprintf(buf, "%s\n", "primary connector+");
44 else
45 return sprintf(buf, "%s\n", "primary connector");
46 case SECONDARY_CONNECTOR:
47 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
48 return sprintf(buf, "%s\n", "secondary connector+");
49 else
50 return sprintf(buf, "%s\n", "secondary connector");
51 default:
52 return sprintf(buf, "%s\n", "no");
53 }
54}
55
56static ssize_t qeth_l3_dev_route4_show(struct device *dev,
57 struct device_attribute *attr, char *buf)
58{
59 struct qeth_card *card = dev_get_drvdata(dev);
60
61 if (!card)
62 return -EINVAL;
63
64 return qeth_l3_dev_route_show(card, &card->options.route4, buf);
65}
66
67static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
68 struct qeth_routing_info *route, enum qeth_prot_versions prot,
69 const char *buf, size_t count)
70{
71 enum qeth_routing_types old_route_type = route->type;
72 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +000073 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +010074
75 tmp = strsep((char **) &buf, "\n");
Frank Blaschkac4949f02010-05-11 19:34:47 +000076 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +010077 if (!strcmp(tmp, "no_router")) {
78 route->type = NO_ROUTER;
79 } else if (!strcmp(tmp, "primary_connector")) {
80 route->type = PRIMARY_CONNECTOR;
81 } else if (!strcmp(tmp, "secondary_connector")) {
82 route->type = SECONDARY_CONNECTOR;
83 } else if (!strcmp(tmp, "primary_router")) {
84 route->type = PRIMARY_ROUTER;
85 } else if (!strcmp(tmp, "secondary_router")) {
86 route->type = SECONDARY_ROUTER;
87 } else if (!strcmp(tmp, "multicast_router")) {
88 route->type = MULTICAST_ROUTER;
89 } else {
Frank Blaschkac4949f02010-05-11 19:34:47 +000090 rc = -EINVAL;
91 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +010092 }
93 if (((card->state == CARD_STATE_SOFTSETUP) ||
94 (card->state == CARD_STATE_UP)) &&
95 (old_route_type != route->type)) {
96 if (prot == QETH_PROT_IPV4)
97 rc = qeth_l3_setrouting_v4(card);
98 else if (prot == QETH_PROT_IPV6)
99 rc = qeth_l3_setrouting_v6(card);
100 }
Frank Blaschkac4949f02010-05-11 19:34:47 +0000101out:
102 mutex_unlock(&card->conf_mutex);
103 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100104}
105
106static ssize_t qeth_l3_dev_route4_store(struct device *dev,
107 struct device_attribute *attr, const char *buf, size_t count)
108{
109 struct qeth_card *card = dev_get_drvdata(dev);
110
111 if (!card)
112 return -EINVAL;
113
114 return qeth_l3_dev_route_store(card, &card->options.route4,
115 QETH_PROT_IPV4, buf, count);
116}
117
118static DEVICE_ATTR(route4, 0644, qeth_l3_dev_route4_show,
119 qeth_l3_dev_route4_store);
120
121static ssize_t qeth_l3_dev_route6_show(struct device *dev,
122 struct device_attribute *attr, char *buf)
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_show(card, &card->options.route6, buf);
130}
131
132static ssize_t qeth_l3_dev_route6_store(struct device *dev,
133 struct device_attribute *attr, const char *buf, size_t count)
134{
135 struct qeth_card *card = dev_get_drvdata(dev);
136
137 if (!card)
138 return -EINVAL;
139
Frank Blaschka4a71df52008-02-15 09:19:42 +0100140 return qeth_l3_dev_route_store(card, &card->options.route6,
141 QETH_PROT_IPV6, buf, count);
142}
143
144static DEVICE_ATTR(route6, 0644, qeth_l3_dev_route6_show,
145 qeth_l3_dev_route6_store);
146
147static ssize_t qeth_l3_dev_fake_broadcast_show(struct device *dev,
148 struct device_attribute *attr, char *buf)
149{
150 struct qeth_card *card = dev_get_drvdata(dev);
151
152 if (!card)
153 return -EINVAL;
154
155 return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0);
156}
157
158static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev,
159 struct device_attribute *attr, const char *buf, size_t count)
160{
161 struct qeth_card *card = dev_get_drvdata(dev);
162 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000163 int i, rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100164
165 if (!card)
166 return -EINVAL;
167
Frank Blaschkac4949f02010-05-11 19:34:47 +0000168 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100169 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000170 (card->state != CARD_STATE_RECOVER)) {
171 rc = -EPERM;
172 goto out;
173 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100174
175 i = simple_strtoul(buf, &tmp, 16);
176 if ((i == 0) || (i == 1))
177 card->options.fake_broadcast = i;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000178 else
179 rc = -EINVAL;
180out:
181 mutex_unlock(&card->conf_mutex);
182 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100183}
184
185static DEVICE_ATTR(fake_broadcast, 0644, qeth_l3_dev_fake_broadcast_show,
186 qeth_l3_dev_fake_broadcast_store);
187
188static ssize_t qeth_l3_dev_broadcast_mode_show(struct device *dev,
189 struct device_attribute *attr, char *buf)
190{
191 struct qeth_card *card = dev_get_drvdata(dev);
192
193 if (!card)
194 return -EINVAL;
195
196 if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
197 (card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
198 return sprintf(buf, "n/a\n");
199
200 return sprintf(buf, "%s\n", (card->options.broadcast_mode ==
201 QETH_TR_BROADCAST_ALLRINGS)?
202 "all rings":"local");
203}
204
205static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev,
206 struct device_attribute *attr, const char *buf, size_t count)
207{
208 struct qeth_card *card = dev_get_drvdata(dev);
209 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000210 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100211
212 if (!card)
213 return -EINVAL;
214
Frank Blaschkac4949f02010-05-11 19:34:47 +0000215 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100216 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000217 (card->state != CARD_STATE_RECOVER)) {
218 rc = -EPERM;
219 goto out;
220 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100221
222 if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
223 (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
Frank Blaschkac4949f02010-05-11 19:34:47 +0000224 rc = -EINVAL;
225 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100226 }
227
228 tmp = strsep((char **) &buf, "\n");
229
Frank Blaschkac4949f02010-05-11 19:34:47 +0000230 if (!strcmp(tmp, "local"))
Frank Blaschka4a71df52008-02-15 09:19:42 +0100231 card->options.broadcast_mode = QETH_TR_BROADCAST_LOCAL;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000232 else if (!strcmp(tmp, "all_rings"))
Frank Blaschka4a71df52008-02-15 09:19:42 +0100233 card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000234 else
235 rc = -EINVAL;
236out:
237 mutex_unlock(&card->conf_mutex);
238 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100239}
240
241static DEVICE_ATTR(broadcast_mode, 0644, qeth_l3_dev_broadcast_mode_show,
242 qeth_l3_dev_broadcast_mode_store);
243
244static ssize_t qeth_l3_dev_canonical_macaddr_show(struct device *dev,
245 struct device_attribute *attr, char *buf)
246{
247 struct qeth_card *card = dev_get_drvdata(dev);
248
249 if (!card)
250 return -EINVAL;
251
252 if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
253 (card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
254 return sprintf(buf, "n/a\n");
255
256 return sprintf(buf, "%i\n", (card->options.macaddr_mode ==
257 QETH_TR_MACADDR_CANONICAL)? 1:0);
258}
259
260static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev,
261 struct device_attribute *attr, const char *buf, size_t count)
262{
263 struct qeth_card *card = dev_get_drvdata(dev);
264 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000265 int i, rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100266
267 if (!card)
268 return -EINVAL;
269
Frank Blaschkac4949f02010-05-11 19:34:47 +0000270 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100271 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000272 (card->state != CARD_STATE_RECOVER)) {
273 rc = -EPERM;
274 goto out;
275 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100276
277 if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
278 (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
Frank Blaschkac4949f02010-05-11 19:34:47 +0000279 rc = -EINVAL;
280 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100281 }
282
283 i = simple_strtoul(buf, &tmp, 16);
284 if ((i == 0) || (i == 1))
285 card->options.macaddr_mode = i?
286 QETH_TR_MACADDR_CANONICAL :
287 QETH_TR_MACADDR_NONCANONICAL;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000288 else
289 rc = -EINVAL;
290out:
291 mutex_unlock(&card->conf_mutex);
292 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100293}
294
295static DEVICE_ATTR(canonical_macaddr, 0644, qeth_l3_dev_canonical_macaddr_show,
296 qeth_l3_dev_canonical_macaddr_store);
297
298static ssize_t qeth_l3_dev_checksum_show(struct device *dev,
299 struct device_attribute *attr, char *buf)
300{
301 struct qeth_card *card = dev_get_drvdata(dev);
302
303 if (!card)
304 return -EINVAL;
305
306 return sprintf(buf, "%s checksumming\n",
307 qeth_l3_get_checksum_str(card));
308}
309
310static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
311 struct device_attribute *attr, const char *buf, size_t count)
312{
313 struct qeth_card *card = dev_get_drvdata(dev);
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000314 enum qeth_checksum_types csum_type;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100315 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000316 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100317
318 if (!card)
319 return -EINVAL;
320
Frank Blaschkac4949f02010-05-11 19:34:47 +0000321 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100322 tmp = strsep((char **) &buf, "\n");
323 if (!strcmp(tmp, "sw_checksumming"))
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000324 csum_type = SW_CHECKSUMMING;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100325 else if (!strcmp(tmp, "hw_checksumming"))
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000326 csum_type = HW_CHECKSUMMING;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100327 else if (!strcmp(tmp, "no_checksumming"))
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000328 csum_type = NO_CHECKSUMMING;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000329 else {
330 rc = -EINVAL;
331 goto out;
332 }
Frank Blaschka3fd434d2009-11-12 00:11:45 +0000333
334 rc = qeth_l3_set_rx_csum(card, csum_type);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000335out:
336 mutex_unlock(&card->conf_mutex);
337 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100338}
339
340static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show,
341 qeth_l3_dev_checksum_store);
342
Ursula Braun76b11f82010-01-11 02:50:50 +0000343static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
344 struct device_attribute *attr, char *buf)
345{
346 struct qeth_card *card = dev_get_drvdata(dev);
347
348 if (!card)
349 return -EINVAL;
350
351 return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
352}
353
354static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
355 struct device_attribute *attr, const char *buf, size_t count)
356{
357 struct qeth_card *card = dev_get_drvdata(dev);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000358 int rc = 0;
Ursula Braun76b11f82010-01-11 02:50:50 +0000359 unsigned long i;
360
361 if (!card)
362 return -EINVAL;
363
364 if (card->info.type != QETH_CARD_TYPE_IQD)
365 return -EPERM;
366
Frank Blaschkac4949f02010-05-11 19:34:47 +0000367 mutex_lock(&card->conf_mutex);
Ursula Braun76b11f82010-01-11 02:50:50 +0000368 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000369 (card->state != CARD_STATE_RECOVER)) {
370 rc = -EPERM;
371 goto out;
372 }
Ursula Braun76b11f82010-01-11 02:50:50 +0000373
Frank Blaschkac4949f02010-05-11 19:34:47 +0000374 rc = strict_strtoul(buf, 16, &i);
375 if (rc) {
376 rc = -EINVAL;
377 goto out;
378 }
Ursula Braun76b11f82010-01-11 02:50:50 +0000379 switch (i) {
380 case 0:
381 card->options.sniffer = i;
382 break;
383 case 1:
Frank Blaschkac4949f02010-05-11 19:34:47 +0000384 qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
Ursula Braun76b11f82010-01-11 02:50:50 +0000385 if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) {
386 card->options.sniffer = i;
387 if (card->qdio.init_pool.buf_count !=
388 QETH_IN_BUF_COUNT_MAX)
389 qeth_realloc_buffer_pool(card,
390 QETH_IN_BUF_COUNT_MAX);
391 break;
392 } else
Frank Blaschkac4949f02010-05-11 19:34:47 +0000393 rc = -EPERM;
Ursula Braun76b11f82010-01-11 02:50:50 +0000394 default: /* fall through */
Frank Blaschkac4949f02010-05-11 19:34:47 +0000395 rc = -EINVAL;
Ursula Braun76b11f82010-01-11 02:50:50 +0000396 }
Frank Blaschkac4949f02010-05-11 19:34:47 +0000397out:
398 mutex_unlock(&card->conf_mutex);
399 return rc ? rc : count;
Ursula Braun76b11f82010-01-11 02:50:50 +0000400}
401
402static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
403 qeth_l3_dev_sniffer_store);
404
Frank Blaschkac3b4a742009-11-12 00:11:44 +0000405static ssize_t qeth_l3_dev_large_send_show(struct device *dev,
406 struct device_attribute *attr, char *buf)
407{
408 struct qeth_card *card = dev_get_drvdata(dev);
409
410 if (!card)
411 return -EINVAL;
412
413 switch (card->options.large_send) {
414 case QETH_LARGE_SEND_NO:
415 return sprintf(buf, "%s\n", "no");
416 case QETH_LARGE_SEND_TSO:
417 return sprintf(buf, "%s\n", "TSO");
418 default:
419 return sprintf(buf, "%s\n", "N/A");
420 }
421}
422
423static ssize_t qeth_l3_dev_large_send_store(struct device *dev,
424 struct device_attribute *attr, const char *buf, size_t count)
425{
426 struct qeth_card *card = dev_get_drvdata(dev);
427 enum qeth_large_send_types type;
428 int rc = 0;
429 char *tmp;
430
431 if (!card)
432 return -EINVAL;
433 tmp = strsep((char **) &buf, "\n");
434 if (!strcmp(tmp, "no"))
435 type = QETH_LARGE_SEND_NO;
436 else if (!strcmp(tmp, "TSO"))
437 type = QETH_LARGE_SEND_TSO;
438 else
439 return -EINVAL;
440
Frank Blaschkac4949f02010-05-11 19:34:47 +0000441 mutex_lock(&card->conf_mutex);
442 if (card->options.large_send != type)
443 rc = qeth_l3_set_large_send(card, type);
444 mutex_unlock(&card->conf_mutex);
445 return rc ? rc : count;
Frank Blaschkac3b4a742009-11-12 00:11:44 +0000446}
447
448static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show,
449 qeth_l3_dev_large_send_store);
450
Frank Blaschka4a71df52008-02-15 09:19:42 +0100451static struct attribute *qeth_l3_device_attrs[] = {
452 &dev_attr_route4.attr,
453 &dev_attr_route6.attr,
454 &dev_attr_fake_broadcast.attr,
455 &dev_attr_broadcast_mode.attr,
456 &dev_attr_canonical_macaddr.attr,
457 &dev_attr_checksumming.attr,
Ursula Braun76b11f82010-01-11 02:50:50 +0000458 &dev_attr_sniffer.attr,
Frank Blaschkac3b4a742009-11-12 00:11:44 +0000459 &dev_attr_large_send.attr,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100460 NULL,
461};
462
463static struct attribute_group qeth_l3_device_attr_group = {
464 .attrs = qeth_l3_device_attrs,
465};
466
467static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev,
468 struct device_attribute *attr, char *buf)
469{
470 struct qeth_card *card = dev_get_drvdata(dev);
471
472 if (!card)
473 return -EINVAL;
474
475 return sprintf(buf, "%i\n", card->ipato.enabled? 1:0);
476}
477
478static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
479 struct device_attribute *attr, const char *buf, size_t count)
480{
481 struct qeth_card *card = dev_get_drvdata(dev);
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000482 struct qeth_ipaddr *tmpipa, *t;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100483 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000484 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100485
486 if (!card)
487 return -EINVAL;
488
Frank Blaschkac4949f02010-05-11 19:34:47 +0000489 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100490 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000491 (card->state != CARD_STATE_RECOVER)) {
492 rc = -EPERM;
493 goto out;
494 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100495
496 tmp = strsep((char **) &buf, "\n");
497 if (!strcmp(tmp, "toggle")) {
498 card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
499 } else if (!strcmp(tmp, "1")) {
500 card->ipato.enabled = 1;
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000501 list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
502 if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
503 qeth_l3_is_addr_covered_by_ipato(card, tmpipa))
504 tmpipa->set_flags |=
505 QETH_IPA_SETIP_TAKEOVER_FLAG;
506 }
507
Frank Blaschka4a71df52008-02-15 09:19:42 +0100508 } else if (!strcmp(tmp, "0")) {
509 card->ipato.enabled = 0;
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000510 list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
511 if (tmpipa->set_flags &
512 QETH_IPA_SETIP_TAKEOVER_FLAG)
513 tmpipa->set_flags &=
514 ~QETH_IPA_SETIP_TAKEOVER_FLAG;
515 }
Frank Blaschkac4949f02010-05-11 19:34:47 +0000516 } else
517 rc = -EINVAL;
518out:
519 mutex_unlock(&card->conf_mutex);
520 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100521}
522
523static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
524 qeth_l3_dev_ipato_enable_show,
525 qeth_l3_dev_ipato_enable_store);
526
527static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev,
528 struct device_attribute *attr, char *buf)
529{
530 struct qeth_card *card = dev_get_drvdata(dev);
531
532 if (!card)
533 return -EINVAL;
534
535 return sprintf(buf, "%i\n", card->ipato.invert4? 1:0);
536}
537
538static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
539 struct device_attribute *attr,
540 const char *buf, size_t count)
541{
542 struct qeth_card *card = dev_get_drvdata(dev);
543 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000544 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100545
546 if (!card)
547 return -EINVAL;
548
Frank Blaschkac4949f02010-05-11 19:34:47 +0000549 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100550 tmp = strsep((char **) &buf, "\n");
551 if (!strcmp(tmp, "toggle")) {
552 card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
553 } else if (!strcmp(tmp, "1")) {
554 card->ipato.invert4 = 1;
555 } else if (!strcmp(tmp, "0")) {
556 card->ipato.invert4 = 0;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000557 } else
558 rc = -EINVAL;
559 mutex_unlock(&card->conf_mutex);
560 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100561}
562
563static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
564 qeth_l3_dev_ipato_invert4_show,
565 qeth_l3_dev_ipato_invert4_store);
566
567static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
568 enum qeth_prot_versions proto)
569{
570 struct qeth_ipato_entry *ipatoe;
571 unsigned long flags;
572 char addr_str[40];
573 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
574 int i = 0;
575
576 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
577 /* add strlen for "/<mask>\n" */
578 entry_len += (proto == QETH_PROT_IPV4)? 5 : 6;
579 spin_lock_irqsave(&card->ip_lock, flags);
580 list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
581 if (ipatoe->proto != proto)
582 continue;
583 /* String must not be longer than PAGE_SIZE. So we check if
584 * string length gets near PAGE_SIZE. Then we can savely display
585 * the next IPv6 address (worst case, compared to IPv4) */
586 if ((PAGE_SIZE - i) <= entry_len)
587 break;
588 qeth_l3_ipaddr_to_string(proto, ipatoe->addr, addr_str);
589 i += snprintf(buf + i, PAGE_SIZE - i,
590 "%s/%i\n", addr_str, ipatoe->mask_bits);
591 }
592 spin_unlock_irqrestore(&card->ip_lock, flags);
593 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
594
595 return i;
596}
597
598static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev,
599 struct device_attribute *attr, char *buf)
600{
601 struct qeth_card *card = dev_get_drvdata(dev);
602
603 if (!card)
604 return -EINVAL;
605
606 return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
607}
608
609static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto,
610 u8 *addr, int *mask_bits)
611{
612 const char *start, *end;
613 char *tmp;
614 char buffer[40] = {0, };
615
616 start = buf;
617 /* get address string */
618 end = strchr(start, '/');
619 if (!end || (end - start >= 40)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100620 return -EINVAL;
621 }
622 strncpy(buffer, start, end - start);
623 if (qeth_l3_string_to_ipaddr(buffer, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100624 return -EINVAL;
625 }
626 start = end + 1;
627 *mask_bits = simple_strtoul(start, &tmp, 10);
628 if (!strlen(start) ||
629 (tmp == start) ||
630 (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100631 return -EINVAL;
632 }
633 return 0;
634}
635
636static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count,
637 struct qeth_card *card, enum qeth_prot_versions proto)
638{
639 struct qeth_ipato_entry *ipatoe;
640 u8 addr[16];
641 int mask_bits;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000642 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100643
Frank Blaschkac4949f02010-05-11 19:34:47 +0000644 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100645 rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
646 if (rc)
Frank Blaschkac4949f02010-05-11 19:34:47 +0000647 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100648
649 ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL);
650 if (!ipatoe) {
Frank Blaschkac4949f02010-05-11 19:34:47 +0000651 rc = -ENOMEM;
652 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100653 }
654 ipatoe->proto = proto;
655 memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4)? 4:16);
656 ipatoe->mask_bits = mask_bits;
657
658 rc = qeth_l3_add_ipato_entry(card, ipatoe);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000659 if (rc)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100660 kfree(ipatoe);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000661out:
662 mutex_unlock(&card->conf_mutex);
663 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100664}
665
666static ssize_t qeth_l3_dev_ipato_add4_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_add_store(buf, count, card, QETH_PROT_IPV4);
675}
676
677static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
678 qeth_l3_dev_ipato_add4_show,
679 qeth_l3_dev_ipato_add4_store);
680
681static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
682 struct qeth_card *card, enum qeth_prot_versions proto)
683{
684 u8 addr[16];
685 int mask_bits;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000686 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100687
Frank Blaschkac4949f02010-05-11 19:34:47 +0000688 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100689 rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000690 if (!rc)
691 qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
692 mutex_unlock(&card->conf_mutex);
693 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100694}
695
696static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev,
697 struct device_attribute *attr, const char *buf, size_t count)
698{
699 struct qeth_card *card = dev_get_drvdata(dev);
700
701 if (!card)
702 return -EINVAL;
703
704 return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4);
705}
706
707static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL,
708 qeth_l3_dev_ipato_del4_store);
709
710static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev,
711 struct device_attribute *attr, char *buf)
712{
713 struct qeth_card *card = dev_get_drvdata(dev);
714
715 if (!card)
716 return -EINVAL;
717
718 return sprintf(buf, "%i\n", card->ipato.invert6? 1:0);
719}
720
721static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
722 struct device_attribute *attr, const char *buf, size_t count)
723{
724 struct qeth_card *card = dev_get_drvdata(dev);
725 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000726 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100727
728 if (!card)
729 return -EINVAL;
730
Frank Blaschkac4949f02010-05-11 19:34:47 +0000731 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100732 tmp = strsep((char **) &buf, "\n");
733 if (!strcmp(tmp, "toggle")) {
734 card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
735 } else if (!strcmp(tmp, "1")) {
736 card->ipato.invert6 = 1;
737 } else if (!strcmp(tmp, "0")) {
738 card->ipato.invert6 = 0;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000739 } else
740 rc = -EINVAL;
741 mutex_unlock(&card->conf_mutex);
742 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100743}
744
745static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
746 qeth_l3_dev_ipato_invert6_show,
747 qeth_l3_dev_ipato_invert6_store);
748
749
750static ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev,
751 struct device_attribute *attr, char *buf)
752{
753 struct qeth_card *card = dev_get_drvdata(dev);
754
755 if (!card)
756 return -EINVAL;
757
758 return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV6);
759}
760
761static ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev,
762 struct device_attribute *attr, const char *buf, size_t count)
763{
764 struct qeth_card *card = dev_get_drvdata(dev);
765
766 if (!card)
767 return -EINVAL;
768
769 return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6);
770}
771
772static QETH_DEVICE_ATTR(ipato_add6, add6, 0644,
773 qeth_l3_dev_ipato_add6_show,
774 qeth_l3_dev_ipato_add6_store);
775
776static ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev,
777 struct device_attribute *attr, const char *buf, size_t count)
778{
779 struct qeth_card *card = dev_get_drvdata(dev);
780
781 if (!card)
782 return -EINVAL;
783
784 return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6);
785}
786
787static QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL,
788 qeth_l3_dev_ipato_del6_store);
789
790static struct attribute *qeth_ipato_device_attrs[] = {
791 &dev_attr_ipato_enable.attr,
792 &dev_attr_ipato_invert4.attr,
793 &dev_attr_ipato_add4.attr,
794 &dev_attr_ipato_del4.attr,
795 &dev_attr_ipato_invert6.attr,
796 &dev_attr_ipato_add6.attr,
797 &dev_attr_ipato_del6.attr,
798 NULL,
799};
800
801static struct attribute_group qeth_device_ipato_group = {
802 .name = "ipa_takeover",
803 .attrs = qeth_ipato_device_attrs,
804};
805
806static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
807 enum qeth_prot_versions proto)
808{
809 struct qeth_ipaddr *ipaddr;
810 char addr_str[40];
811 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
812 unsigned long flags;
813 int i = 0;
814
815 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
816 entry_len += 2; /* \n + terminator */
817 spin_lock_irqsave(&card->ip_lock, flags);
818 list_for_each_entry(ipaddr, &card->ip_list, entry) {
819 if (ipaddr->proto != proto)
820 continue;
821 if (ipaddr->type != QETH_IP_TYPE_VIPA)
822 continue;
823 /* String must not be longer than PAGE_SIZE. So we check if
824 * string length gets near PAGE_SIZE. Then we can savely display
825 * the next IPv6 address (worst case, compared to IPv4) */
826 if ((PAGE_SIZE - i) <= entry_len)
827 break;
828 qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
829 addr_str);
830 i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
831 }
832 spin_unlock_irqrestore(&card->ip_lock, flags);
833 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
834
835 return i;
836}
837
838static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev,
839 struct device_attribute *attr, char *buf)
840{
841 struct qeth_card *card = dev_get_drvdata(dev);
842
843 if (!card)
844 return -EINVAL;
845
846 return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
847}
848
849static int qeth_l3_parse_vipae(const char *buf, enum qeth_prot_versions proto,
850 u8 *addr)
851{
852 if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100853 return -EINVAL;
854 }
855 return 0;
856}
857
858static ssize_t qeth_l3_dev_vipa_add_store(const char *buf, size_t count,
859 struct qeth_card *card, enum qeth_prot_versions proto)
860{
861 u8 addr[16] = {0, };
862 int rc;
863
Frank Blaschkac4949f02010-05-11 19:34:47 +0000864 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100865 rc = qeth_l3_parse_vipae(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000866 if (!rc)
867 rc = qeth_l3_add_vipa(card, proto, addr);
868 mutex_unlock(&card->conf_mutex);
869 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100870}
871
872static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev,
873 struct device_attribute *attr, const char *buf, size_t count)
874{
875 struct qeth_card *card = dev_get_drvdata(dev);
876
877 if (!card)
878 return -EINVAL;
879
880 return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV4);
881}
882
883static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
884 qeth_l3_dev_vipa_add4_show,
885 qeth_l3_dev_vipa_add4_store);
886
887static ssize_t qeth_l3_dev_vipa_del_store(const char *buf, size_t count,
888 struct qeth_card *card, enum qeth_prot_versions proto)
889{
890 u8 addr[16];
891 int rc;
892
Frank Blaschkac4949f02010-05-11 19:34:47 +0000893 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100894 rc = qeth_l3_parse_vipae(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000895 if (!rc)
896 qeth_l3_del_vipa(card, proto, addr);
897 mutex_unlock(&card->conf_mutex);
898 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100899}
900
901static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev,
902 struct device_attribute *attr, const char *buf, size_t count)
903{
904 struct qeth_card *card = dev_get_drvdata(dev);
905
906 if (!card)
907 return -EINVAL;
908
909 return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV4);
910}
911
912static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL,
913 qeth_l3_dev_vipa_del4_store);
914
915static ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev,
916 struct device_attribute *attr, char *buf)
917{
918 struct qeth_card *card = dev_get_drvdata(dev);
919
920 if (!card)
921 return -EINVAL;
922
923 return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV6);
924}
925
926static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev,
927 struct device_attribute *attr, const char *buf, size_t count)
928{
929 struct qeth_card *card = dev_get_drvdata(dev);
930
931 if (!card)
932 return -EINVAL;
933
934 return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV6);
935}
936
937static QETH_DEVICE_ATTR(vipa_add6, add6, 0644,
938 qeth_l3_dev_vipa_add6_show,
939 qeth_l3_dev_vipa_add6_store);
940
941static ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev,
942 struct device_attribute *attr, const char *buf, size_t count)
943{
944 struct qeth_card *card = dev_get_drvdata(dev);
945
946 if (!card)
947 return -EINVAL;
948
949 return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6);
950}
951
952static QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL,
953 qeth_l3_dev_vipa_del6_store);
954
955static struct attribute *qeth_vipa_device_attrs[] = {
956 &dev_attr_vipa_add4.attr,
957 &dev_attr_vipa_del4.attr,
958 &dev_attr_vipa_add6.attr,
959 &dev_attr_vipa_del6.attr,
960 NULL,
961};
962
963static struct attribute_group qeth_device_vipa_group = {
964 .name = "vipa",
965 .attrs = qeth_vipa_device_attrs,
966};
967
968static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
969 enum qeth_prot_versions proto)
970{
971 struct qeth_ipaddr *ipaddr;
972 char addr_str[40];
973 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
974 unsigned long flags;
975 int i = 0;
976
977 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
978 entry_len += 2; /* \n + terminator */
979 spin_lock_irqsave(&card->ip_lock, flags);
980 list_for_each_entry(ipaddr, &card->ip_list, entry) {
981 if (ipaddr->proto != proto)
982 continue;
983 if (ipaddr->type != QETH_IP_TYPE_RXIP)
984 continue;
985 /* String must not be longer than PAGE_SIZE. So we check if
986 * string length gets near PAGE_SIZE. Then we can savely display
987 * the next IPv6 address (worst case, compared to IPv4) */
988 if ((PAGE_SIZE - i) <= entry_len)
989 break;
990 qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
991 addr_str);
992 i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
993 }
994 spin_unlock_irqrestore(&card->ip_lock, flags);
995 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
996
997 return i;
998}
999
1000static ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev,
1001 struct device_attribute *attr, char *buf)
1002{
1003 struct qeth_card *card = dev_get_drvdata(dev);
1004
1005 if (!card)
1006 return -EINVAL;
1007
1008 return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
1009}
1010
1011static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto,
1012 u8 *addr)
1013{
1014 if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +01001015 return -EINVAL;
1016 }
1017 return 0;
1018}
1019
1020static ssize_t qeth_l3_dev_rxip_add_store(const char *buf, size_t count,
1021 struct qeth_card *card, enum qeth_prot_versions proto)
1022{
1023 u8 addr[16] = {0, };
1024 int rc;
1025
Frank Blaschkac4949f02010-05-11 19:34:47 +00001026 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001027 rc = qeth_l3_parse_rxipe(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +00001028 if (!rc)
1029 rc = qeth_l3_add_rxip(card, proto, addr);
1030 mutex_unlock(&card->conf_mutex);
1031 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001032}
1033
1034static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev,
1035 struct device_attribute *attr, const char *buf, size_t count)
1036{
1037 struct qeth_card *card = dev_get_drvdata(dev);
1038
1039 if (!card)
1040 return -EINVAL;
1041
1042 return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV4);
1043}
1044
1045static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
1046 qeth_l3_dev_rxip_add4_show,
1047 qeth_l3_dev_rxip_add4_store);
1048
1049static ssize_t qeth_l3_dev_rxip_del_store(const char *buf, size_t count,
1050 struct qeth_card *card, enum qeth_prot_versions proto)
1051{
1052 u8 addr[16];
1053 int rc;
1054
Frank Blaschkac4949f02010-05-11 19:34:47 +00001055 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +01001056 rc = qeth_l3_parse_rxipe(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +00001057 if (!rc)
1058 qeth_l3_del_rxip(card, proto, addr);
1059 mutex_unlock(&card->conf_mutex);
1060 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +01001061}
1062
1063static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev,
1064 struct device_attribute *attr, const char *buf, size_t count)
1065{
1066 struct qeth_card *card = dev_get_drvdata(dev);
1067
1068 if (!card)
1069 return -EINVAL;
1070
1071 return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV4);
1072}
1073
1074static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL,
1075 qeth_l3_dev_rxip_del4_store);
1076
1077static ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev,
1078 struct device_attribute *attr, char *buf)
1079{
1080 struct qeth_card *card = dev_get_drvdata(dev);
1081
1082 if (!card)
1083 return -EINVAL;
1084
1085 return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV6);
1086}
1087
1088static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev,
1089 struct device_attribute *attr, const char *buf, size_t count)
1090{
1091 struct qeth_card *card = dev_get_drvdata(dev);
1092
1093 if (!card)
1094 return -EINVAL;
1095
1096 return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV6);
1097}
1098
1099static QETH_DEVICE_ATTR(rxip_add6, add6, 0644,
1100 qeth_l3_dev_rxip_add6_show,
1101 qeth_l3_dev_rxip_add6_store);
1102
1103static ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev,
1104 struct device_attribute *attr, const char *buf, size_t count)
1105{
1106 struct qeth_card *card = dev_get_drvdata(dev);
1107
1108 if (!card)
1109 return -EINVAL;
1110
1111 return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV6);
1112}
1113
1114static QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL,
1115 qeth_l3_dev_rxip_del6_store);
1116
1117static struct attribute *qeth_rxip_device_attrs[] = {
1118 &dev_attr_rxip_add4.attr,
1119 &dev_attr_rxip_del4.attr,
1120 &dev_attr_rxip_add6.attr,
1121 &dev_attr_rxip_del6.attr,
1122 NULL,
1123};
1124
1125static struct attribute_group qeth_device_rxip_group = {
1126 .name = "rxip",
1127 .attrs = qeth_rxip_device_attrs,
1128};
1129
1130int qeth_l3_create_device_attributes(struct device *dev)
1131{
1132 int ret;
1133
1134 ret = sysfs_create_group(&dev->kobj, &qeth_l3_device_attr_group);
1135 if (ret)
1136 return ret;
1137
1138 ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group);
1139 if (ret) {
1140 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1141 return ret;
1142 }
1143
1144 ret = sysfs_create_group(&dev->kobj, &qeth_device_vipa_group);
1145 if (ret) {
1146 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1147 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1148 return ret;
1149 }
1150
1151 ret = sysfs_create_group(&dev->kobj, &qeth_device_rxip_group);
1152 if (ret) {
1153 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1154 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1155 sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
1156 return ret;
1157 }
1158 return 0;
1159}
1160
1161void qeth_l3_remove_device_attributes(struct device *dev)
1162{
1163 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1164 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1165 sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
1166 sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
1167}