blob: adef5f5de118a7ed9b320b3cea07672bc511ec36 [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 }
81 if (((card->state == CARD_STATE_SOFTSETUP) ||
82 (card->state == CARD_STATE_UP)) &&
83 (old_route_type != route->type)) {
84 if (prot == QETH_PROT_IPV4)
85 rc = qeth_l3_setrouting_v4(card);
86 else if (prot == QETH_PROT_IPV6)
87 rc = qeth_l3_setrouting_v6(card);
88 }
Frank Blaschkac4949f02010-05-11 19:34:47 +000089out:
Stefan Raspl82e2e782013-03-18 20:04:43 +000090 if (rc)
91 route->type = old_route_type;
Frank Blaschkac4949f02010-05-11 19:34:47 +000092 mutex_unlock(&card->conf_mutex);
93 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +010094}
95
96static ssize_t qeth_l3_dev_route4_store(struct device *dev,
97 struct device_attribute *attr, const char *buf, size_t count)
98{
99 struct qeth_card *card = dev_get_drvdata(dev);
100
101 if (!card)
102 return -EINVAL;
103
104 return qeth_l3_dev_route_store(card, &card->options.route4,
105 QETH_PROT_IPV4, buf, count);
106}
107
108static DEVICE_ATTR(route4, 0644, qeth_l3_dev_route4_show,
109 qeth_l3_dev_route4_store);
110
111static ssize_t qeth_l3_dev_route6_show(struct device *dev,
112 struct device_attribute *attr, char *buf)
113{
114 struct qeth_card *card = dev_get_drvdata(dev);
115
116 if (!card)
117 return -EINVAL;
118
Frank Blaschka4a71df52008-02-15 09:19:42 +0100119 return qeth_l3_dev_route_show(card, &card->options.route6, buf);
120}
121
122static ssize_t qeth_l3_dev_route6_store(struct device *dev,
123 struct device_attribute *attr, const char *buf, size_t count)
124{
125 struct qeth_card *card = dev_get_drvdata(dev);
126
127 if (!card)
128 return -EINVAL;
129
Frank Blaschka4a71df52008-02-15 09:19:42 +0100130 return qeth_l3_dev_route_store(card, &card->options.route6,
131 QETH_PROT_IPV6, buf, count);
132}
133
134static DEVICE_ATTR(route6, 0644, qeth_l3_dev_route6_show,
135 qeth_l3_dev_route6_store);
136
137static ssize_t qeth_l3_dev_fake_broadcast_show(struct device *dev,
138 struct device_attribute *attr, char *buf)
139{
140 struct qeth_card *card = dev_get_drvdata(dev);
141
142 if (!card)
143 return -EINVAL;
144
145 return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0);
146}
147
148static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev,
149 struct device_attribute *attr, const char *buf, size_t count)
150{
151 struct qeth_card *card = dev_get_drvdata(dev);
152 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000153 int i, rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100154
155 if (!card)
156 return -EINVAL;
157
Frank Blaschkac4949f02010-05-11 19:34:47 +0000158 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100159 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000160 (card->state != CARD_STATE_RECOVER)) {
161 rc = -EPERM;
162 goto out;
163 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100164
165 i = simple_strtoul(buf, &tmp, 16);
166 if ((i == 0) || (i == 1))
167 card->options.fake_broadcast = i;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000168 else
169 rc = -EINVAL;
170out:
171 mutex_unlock(&card->conf_mutex);
172 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100173}
174
175static DEVICE_ATTR(fake_broadcast, 0644, qeth_l3_dev_fake_broadcast_show,
176 qeth_l3_dev_fake_broadcast_store);
177
Ursula Braun76b11f82010-01-11 02:50:50 +0000178static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
179 struct device_attribute *attr, char *buf)
180{
181 struct qeth_card *card = dev_get_drvdata(dev);
182
183 if (!card)
184 return -EINVAL;
185
186 return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
187}
188
189static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
190 struct device_attribute *attr, const char *buf, size_t count)
191{
192 struct qeth_card *card = dev_get_drvdata(dev);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000193 int rc = 0;
Ursula Braun76b11f82010-01-11 02:50:50 +0000194 unsigned long i;
195
196 if (!card)
197 return -EINVAL;
198
199 if (card->info.type != QETH_CARD_TYPE_IQD)
200 return -EPERM;
Frank Blaschkab3332932011-08-08 01:33:59 +0000201 if (card->options.cq == QETH_CQ_ENABLED)
202 return -EPERM;
Ursula Braun76b11f82010-01-11 02:50:50 +0000203
Frank Blaschkac4949f02010-05-11 19:34:47 +0000204 mutex_lock(&card->conf_mutex);
Ursula Braun76b11f82010-01-11 02:50:50 +0000205 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000206 (card->state != CARD_STATE_RECOVER)) {
207 rc = -EPERM;
208 goto out;
209 }
Ursula Braun76b11f82010-01-11 02:50:50 +0000210
Jingoo Han01787222013-07-22 10:18:15 +0900211 rc = kstrtoul(buf, 16, &i);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000212 if (rc) {
213 rc = -EINVAL;
214 goto out;
215 }
Ursula Braun76b11f82010-01-11 02:50:50 +0000216 switch (i) {
217 case 0:
218 card->options.sniffer = i;
219 break;
220 case 1:
Frank Blaschkac4949f02010-05-11 19:34:47 +0000221 qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
Ursula Braun76b11f82010-01-11 02:50:50 +0000222 if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) {
223 card->options.sniffer = i;
224 if (card->qdio.init_pool.buf_count !=
225 QETH_IN_BUF_COUNT_MAX)
226 qeth_realloc_buffer_pool(card,
227 QETH_IN_BUF_COUNT_MAX);
Ursula Braun76b11f82010-01-11 02:50:50 +0000228 } else
Frank Blaschkac4949f02010-05-11 19:34:47 +0000229 rc = -EPERM;
Ursula Braun6cc31d02011-11-15 02:31:12 +0000230 break;
231 default:
Frank Blaschkac4949f02010-05-11 19:34:47 +0000232 rc = -EINVAL;
Ursula Braun76b11f82010-01-11 02:50:50 +0000233 }
Frank Blaschkac4949f02010-05-11 19:34:47 +0000234out:
235 mutex_unlock(&card->conf_mutex);
236 return rc ? rc : count;
Ursula Braun76b11f82010-01-11 02:50:50 +0000237}
238
239static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
240 qeth_l3_dev_sniffer_store);
241
Frank Blaschkab3332932011-08-08 01:33:59 +0000242
243static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
244 struct device_attribute *attr, char *buf)
245{
246 struct qeth_card *card = dev_get_drvdata(dev);
247 char tmp_hsuid[9];
248
249 if (!card)
250 return -EINVAL;
251
252 if (card->info.type != QETH_CARD_TYPE_IQD)
253 return -EPERM;
254
255 if (card->state == CARD_STATE_DOWN)
256 return -EPERM;
257
258 memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid));
259 EBCASC(tmp_hsuid, 8);
260 return sprintf(buf, "%s\n", tmp_hsuid);
261}
262
263static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
264 struct device_attribute *attr, const char *buf, size_t count)
265{
266 struct qeth_card *card = dev_get_drvdata(dev);
267 struct qeth_ipaddr *addr;
268 char *tmp;
269 int i;
270
271 if (!card)
272 return -EINVAL;
273
274 if (card->info.type != QETH_CARD_TYPE_IQD)
275 return -EPERM;
276 if (card->state != CARD_STATE_DOWN &&
277 card->state != CARD_STATE_RECOVER)
278 return -EPERM;
279 if (card->options.sniffer)
280 return -EPERM;
281 if (card->options.cq == QETH_CQ_NOTAVAILABLE)
282 return -EPERM;
283
284 tmp = strsep((char **)&buf, "\n");
285 if (strlen(tmp) > 8)
286 return -EINVAL;
287
288 if (card->options.hsuid[0]) {
289 /* delete old ip address */
290 addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
291 if (addr != NULL) {
292 addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
293 addr->u.a6.addr.s6_addr32[1] = 0x00000000;
294 for (i = 8; i < 16; i++)
295 addr->u.a6.addr.s6_addr[i] =
296 card->options.hsuid[i - 8];
297 addr->u.a6.pfxlen = 0;
298 addr->type = QETH_IP_TYPE_NORMAL;
299 } else
300 return -ENOMEM;
301 if (!qeth_l3_delete_ip(card, addr))
302 kfree(addr);
303 qeth_l3_set_ip_addr_list(card);
304 }
305
306 if (strlen(tmp) == 0) {
307 /* delete ip address only */
308 card->options.hsuid[0] = '\0';
309 if (card->dev)
310 memcpy(card->dev->perm_addr, card->options.hsuid, 9);
311 qeth_configure_cq(card, QETH_CQ_DISABLED);
312 return count;
313 }
314
315 if (qeth_configure_cq(card, QETH_CQ_ENABLED))
316 return -EPERM;
317
Kees Cook096a8aa2013-07-03 15:04:55 -0700318 snprintf(card->options.hsuid, sizeof(card->options.hsuid),
319 "%-8s", tmp);
Frank Blaschkab3332932011-08-08 01:33:59 +0000320 ASCEBC(card->options.hsuid, 8);
321 if (card->dev)
322 memcpy(card->dev->perm_addr, card->options.hsuid, 9);
323
324 addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
325 if (addr != NULL) {
326 addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
327 addr->u.a6.addr.s6_addr32[1] = 0x00000000;
328 for (i = 8; i < 16; i++)
329 addr->u.a6.addr.s6_addr[i] = card->options.hsuid[i - 8];
330 addr->u.a6.pfxlen = 0;
331 addr->type = QETH_IP_TYPE_NORMAL;
332 } else
333 return -ENOMEM;
334 if (!qeth_l3_add_ip(card, addr))
335 kfree(addr);
336 qeth_l3_set_ip_addr_list(card);
337
338 return count;
339}
340
341static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show,
342 qeth_l3_dev_hsuid_store);
343
344
Frank Blaschka4a71df52008-02-15 09:19:42 +0100345static struct attribute *qeth_l3_device_attrs[] = {
346 &dev_attr_route4.attr,
347 &dev_attr_route6.attr,
348 &dev_attr_fake_broadcast.attr,
Ursula Braun76b11f82010-01-11 02:50:50 +0000349 &dev_attr_sniffer.attr,
Frank Blaschkab3332932011-08-08 01:33:59 +0000350 &dev_attr_hsuid.attr,
Frank Blaschka4a71df52008-02-15 09:19:42 +0100351 NULL,
352};
353
354static struct attribute_group qeth_l3_device_attr_group = {
355 .attrs = qeth_l3_device_attrs,
356};
357
358static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev,
359 struct device_attribute *attr, char *buf)
360{
361 struct qeth_card *card = dev_get_drvdata(dev);
362
363 if (!card)
364 return -EINVAL;
365
366 return sprintf(buf, "%i\n", card->ipato.enabled? 1:0);
367}
368
369static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
370 struct device_attribute *attr, const char *buf, size_t count)
371{
372 struct qeth_card *card = dev_get_drvdata(dev);
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000373 struct qeth_ipaddr *tmpipa, *t;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100374 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000375 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100376
377 if (!card)
378 return -EINVAL;
379
Frank Blaschkac4949f02010-05-11 19:34:47 +0000380 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100381 if ((card->state != CARD_STATE_DOWN) &&
Frank Blaschkac4949f02010-05-11 19:34:47 +0000382 (card->state != CARD_STATE_RECOVER)) {
383 rc = -EPERM;
384 goto out;
385 }
Frank Blaschka4a71df52008-02-15 09:19:42 +0100386
387 tmp = strsep((char **) &buf, "\n");
388 if (!strcmp(tmp, "toggle")) {
389 card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
390 } else if (!strcmp(tmp, "1")) {
391 card->ipato.enabled = 1;
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000392 list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
393 if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
394 qeth_l3_is_addr_covered_by_ipato(card, tmpipa))
395 tmpipa->set_flags |=
396 QETH_IPA_SETIP_TAKEOVER_FLAG;
397 }
398
Frank Blaschka4a71df52008-02-15 09:19:42 +0100399 } else if (!strcmp(tmp, "0")) {
400 card->ipato.enabled = 0;
Klaus-Dieter Wacker62982632010-07-22 23:15:03 +0000401 list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
402 if (tmpipa->set_flags &
403 QETH_IPA_SETIP_TAKEOVER_FLAG)
404 tmpipa->set_flags &=
405 ~QETH_IPA_SETIP_TAKEOVER_FLAG;
406 }
Frank Blaschkac4949f02010-05-11 19:34:47 +0000407 } else
408 rc = -EINVAL;
409out:
410 mutex_unlock(&card->conf_mutex);
411 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100412}
413
414static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
415 qeth_l3_dev_ipato_enable_show,
416 qeth_l3_dev_ipato_enable_store);
417
418static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev,
419 struct device_attribute *attr, char *buf)
420{
421 struct qeth_card *card = dev_get_drvdata(dev);
422
423 if (!card)
424 return -EINVAL;
425
426 return sprintf(buf, "%i\n", card->ipato.invert4? 1:0);
427}
428
429static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
430 struct device_attribute *attr,
431 const char *buf, size_t count)
432{
433 struct qeth_card *card = dev_get_drvdata(dev);
434 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000435 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100436
437 if (!card)
438 return -EINVAL;
439
Frank Blaschkac4949f02010-05-11 19:34:47 +0000440 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100441 tmp = strsep((char **) &buf, "\n");
442 if (!strcmp(tmp, "toggle")) {
443 card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
444 } else if (!strcmp(tmp, "1")) {
445 card->ipato.invert4 = 1;
446 } else if (!strcmp(tmp, "0")) {
447 card->ipato.invert4 = 0;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000448 } else
449 rc = -EINVAL;
450 mutex_unlock(&card->conf_mutex);
451 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100452}
453
454static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
455 qeth_l3_dev_ipato_invert4_show,
456 qeth_l3_dev_ipato_invert4_store);
457
458static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
459 enum qeth_prot_versions proto)
460{
461 struct qeth_ipato_entry *ipatoe;
462 unsigned long flags;
463 char addr_str[40];
464 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
465 int i = 0;
466
467 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
468 /* add strlen for "/<mask>\n" */
469 entry_len += (proto == QETH_PROT_IPV4)? 5 : 6;
470 spin_lock_irqsave(&card->ip_lock, flags);
471 list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
472 if (ipatoe->proto != proto)
473 continue;
474 /* String must not be longer than PAGE_SIZE. So we check if
475 * string length gets near PAGE_SIZE. Then we can savely display
476 * the next IPv6 address (worst case, compared to IPv4) */
477 if ((PAGE_SIZE - i) <= entry_len)
478 break;
479 qeth_l3_ipaddr_to_string(proto, ipatoe->addr, addr_str);
480 i += snprintf(buf + i, PAGE_SIZE - i,
481 "%s/%i\n", addr_str, ipatoe->mask_bits);
482 }
483 spin_unlock_irqrestore(&card->ip_lock, flags);
484 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
485
486 return i;
487}
488
489static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev,
490 struct device_attribute *attr, char *buf)
491{
492 struct qeth_card *card = dev_get_drvdata(dev);
493
494 if (!card)
495 return -EINVAL;
496
497 return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
498}
499
500static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto,
501 u8 *addr, int *mask_bits)
502{
503 const char *start, *end;
504 char *tmp;
505 char buffer[40] = {0, };
506
507 start = buf;
508 /* get address string */
509 end = strchr(start, '/');
510 if (!end || (end - start >= 40)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100511 return -EINVAL;
512 }
513 strncpy(buffer, start, end - start);
514 if (qeth_l3_string_to_ipaddr(buffer, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100515 return -EINVAL;
516 }
517 start = end + 1;
518 *mask_bits = simple_strtoul(start, &tmp, 10);
519 if (!strlen(start) ||
520 (tmp == start) ||
521 (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100522 return -EINVAL;
523 }
524 return 0;
525}
526
527static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count,
528 struct qeth_card *card, enum qeth_prot_versions proto)
529{
530 struct qeth_ipato_entry *ipatoe;
531 u8 addr[16];
532 int mask_bits;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000533 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100534
Frank Blaschkac4949f02010-05-11 19:34:47 +0000535 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100536 rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
537 if (rc)
Frank Blaschkac4949f02010-05-11 19:34:47 +0000538 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100539
540 ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL);
541 if (!ipatoe) {
Frank Blaschkac4949f02010-05-11 19:34:47 +0000542 rc = -ENOMEM;
543 goto out;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100544 }
545 ipatoe->proto = proto;
546 memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4)? 4:16);
547 ipatoe->mask_bits = mask_bits;
548
549 rc = qeth_l3_add_ipato_entry(card, ipatoe);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000550 if (rc)
Frank Blaschka4a71df52008-02-15 09:19:42 +0100551 kfree(ipatoe);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000552out:
553 mutex_unlock(&card->conf_mutex);
554 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100555}
556
557static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev,
558 struct device_attribute *attr, const char *buf, size_t count)
559{
560 struct qeth_card *card = dev_get_drvdata(dev);
561
562 if (!card)
563 return -EINVAL;
564
565 return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4);
566}
567
568static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
569 qeth_l3_dev_ipato_add4_show,
570 qeth_l3_dev_ipato_add4_store);
571
572static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
573 struct qeth_card *card, enum qeth_prot_versions proto)
574{
575 u8 addr[16];
576 int mask_bits;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000577 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100578
Frank Blaschkac4949f02010-05-11 19:34:47 +0000579 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100580 rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000581 if (!rc)
582 qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
583 mutex_unlock(&card->conf_mutex);
584 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100585}
586
587static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev,
588 struct device_attribute *attr, const char *buf, size_t count)
589{
590 struct qeth_card *card = dev_get_drvdata(dev);
591
592 if (!card)
593 return -EINVAL;
594
595 return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4);
596}
597
598static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL,
599 qeth_l3_dev_ipato_del4_store);
600
601static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev,
602 struct device_attribute *attr, char *buf)
603{
604 struct qeth_card *card = dev_get_drvdata(dev);
605
606 if (!card)
607 return -EINVAL;
608
609 return sprintf(buf, "%i\n", card->ipato.invert6? 1:0);
610}
611
612static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
613 struct device_attribute *attr, const char *buf, size_t count)
614{
615 struct qeth_card *card = dev_get_drvdata(dev);
616 char *tmp;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000617 int rc = 0;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100618
619 if (!card)
620 return -EINVAL;
621
Frank Blaschkac4949f02010-05-11 19:34:47 +0000622 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100623 tmp = strsep((char **) &buf, "\n");
624 if (!strcmp(tmp, "toggle")) {
625 card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
626 } else if (!strcmp(tmp, "1")) {
627 card->ipato.invert6 = 1;
628 } else if (!strcmp(tmp, "0")) {
629 card->ipato.invert6 = 0;
Frank Blaschkac4949f02010-05-11 19:34:47 +0000630 } else
631 rc = -EINVAL;
632 mutex_unlock(&card->conf_mutex);
633 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100634}
635
636static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
637 qeth_l3_dev_ipato_invert6_show,
638 qeth_l3_dev_ipato_invert6_store);
639
640
641static ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev,
642 struct device_attribute *attr, char *buf)
643{
644 struct qeth_card *card = dev_get_drvdata(dev);
645
646 if (!card)
647 return -EINVAL;
648
649 return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV6);
650}
651
652static ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev,
653 struct device_attribute *attr, const char *buf, size_t count)
654{
655 struct qeth_card *card = dev_get_drvdata(dev);
656
657 if (!card)
658 return -EINVAL;
659
660 return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6);
661}
662
663static QETH_DEVICE_ATTR(ipato_add6, add6, 0644,
664 qeth_l3_dev_ipato_add6_show,
665 qeth_l3_dev_ipato_add6_store);
666
667static ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev,
668 struct device_attribute *attr, const char *buf, size_t count)
669{
670 struct qeth_card *card = dev_get_drvdata(dev);
671
672 if (!card)
673 return -EINVAL;
674
675 return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6);
676}
677
678static QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL,
679 qeth_l3_dev_ipato_del6_store);
680
681static struct attribute *qeth_ipato_device_attrs[] = {
682 &dev_attr_ipato_enable.attr,
683 &dev_attr_ipato_invert4.attr,
684 &dev_attr_ipato_add4.attr,
685 &dev_attr_ipato_del4.attr,
686 &dev_attr_ipato_invert6.attr,
687 &dev_attr_ipato_add6.attr,
688 &dev_attr_ipato_del6.attr,
689 NULL,
690};
691
692static struct attribute_group qeth_device_ipato_group = {
693 .name = "ipa_takeover",
694 .attrs = qeth_ipato_device_attrs,
695};
696
697static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
698 enum qeth_prot_versions proto)
699{
700 struct qeth_ipaddr *ipaddr;
701 char addr_str[40];
702 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
703 unsigned long flags;
704 int i = 0;
705
706 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
707 entry_len += 2; /* \n + terminator */
708 spin_lock_irqsave(&card->ip_lock, flags);
709 list_for_each_entry(ipaddr, &card->ip_list, entry) {
710 if (ipaddr->proto != proto)
711 continue;
712 if (ipaddr->type != QETH_IP_TYPE_VIPA)
713 continue;
714 /* String must not be longer than PAGE_SIZE. So we check if
715 * string length gets near PAGE_SIZE. Then we can savely display
716 * the next IPv6 address (worst case, compared to IPv4) */
717 if ((PAGE_SIZE - i) <= entry_len)
718 break;
719 qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
720 addr_str);
721 i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
722 }
723 spin_unlock_irqrestore(&card->ip_lock, flags);
724 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
725
726 return i;
727}
728
729static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev,
730 struct device_attribute *attr, char *buf)
731{
732 struct qeth_card *card = dev_get_drvdata(dev);
733
734 if (!card)
735 return -EINVAL;
736
737 return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
738}
739
740static int qeth_l3_parse_vipae(const char *buf, enum qeth_prot_versions proto,
741 u8 *addr)
742{
743 if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100744 return -EINVAL;
745 }
746 return 0;
747}
748
749static ssize_t qeth_l3_dev_vipa_add_store(const char *buf, size_t count,
750 struct qeth_card *card, enum qeth_prot_versions proto)
751{
752 u8 addr[16] = {0, };
753 int rc;
754
Frank Blaschkac4949f02010-05-11 19:34:47 +0000755 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100756 rc = qeth_l3_parse_vipae(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000757 if (!rc)
758 rc = qeth_l3_add_vipa(card, proto, addr);
759 mutex_unlock(&card->conf_mutex);
760 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100761}
762
763static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev,
764 struct device_attribute *attr, const char *buf, size_t count)
765{
766 struct qeth_card *card = dev_get_drvdata(dev);
767
768 if (!card)
769 return -EINVAL;
770
771 return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV4);
772}
773
774static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
775 qeth_l3_dev_vipa_add4_show,
776 qeth_l3_dev_vipa_add4_store);
777
778static ssize_t qeth_l3_dev_vipa_del_store(const char *buf, size_t count,
779 struct qeth_card *card, enum qeth_prot_versions proto)
780{
781 u8 addr[16];
782 int rc;
783
Frank Blaschkac4949f02010-05-11 19:34:47 +0000784 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100785 rc = qeth_l3_parse_vipae(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000786 if (!rc)
787 qeth_l3_del_vipa(card, proto, addr);
788 mutex_unlock(&card->conf_mutex);
789 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100790}
791
792static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev,
793 struct device_attribute *attr, const char *buf, size_t count)
794{
795 struct qeth_card *card = dev_get_drvdata(dev);
796
797 if (!card)
798 return -EINVAL;
799
800 return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV4);
801}
802
803static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL,
804 qeth_l3_dev_vipa_del4_store);
805
806static ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev,
807 struct device_attribute *attr, char *buf)
808{
809 struct qeth_card *card = dev_get_drvdata(dev);
810
811 if (!card)
812 return -EINVAL;
813
814 return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV6);
815}
816
817static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev,
818 struct device_attribute *attr, const char *buf, size_t count)
819{
820 struct qeth_card *card = dev_get_drvdata(dev);
821
822 if (!card)
823 return -EINVAL;
824
825 return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV6);
826}
827
828static QETH_DEVICE_ATTR(vipa_add6, add6, 0644,
829 qeth_l3_dev_vipa_add6_show,
830 qeth_l3_dev_vipa_add6_store);
831
832static ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev,
833 struct device_attribute *attr, const char *buf, size_t count)
834{
835 struct qeth_card *card = dev_get_drvdata(dev);
836
837 if (!card)
838 return -EINVAL;
839
840 return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6);
841}
842
843static QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL,
844 qeth_l3_dev_vipa_del6_store);
845
846static struct attribute *qeth_vipa_device_attrs[] = {
847 &dev_attr_vipa_add4.attr,
848 &dev_attr_vipa_del4.attr,
849 &dev_attr_vipa_add6.attr,
850 &dev_attr_vipa_del6.attr,
851 NULL,
852};
853
854static struct attribute_group qeth_device_vipa_group = {
855 .name = "vipa",
856 .attrs = qeth_vipa_device_attrs,
857};
858
859static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
860 enum qeth_prot_versions proto)
861{
862 struct qeth_ipaddr *ipaddr;
863 char addr_str[40];
864 int entry_len; /* length of 1 entry string, differs between v4 and v6 */
865 unsigned long flags;
866 int i = 0;
867
868 entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
869 entry_len += 2; /* \n + terminator */
870 spin_lock_irqsave(&card->ip_lock, flags);
871 list_for_each_entry(ipaddr, &card->ip_list, entry) {
872 if (ipaddr->proto != proto)
873 continue;
874 if (ipaddr->type != QETH_IP_TYPE_RXIP)
875 continue;
876 /* String must not be longer than PAGE_SIZE. So we check if
877 * string length gets near PAGE_SIZE. Then we can savely display
878 * the next IPv6 address (worst case, compared to IPv4) */
879 if ((PAGE_SIZE - i) <= entry_len)
880 break;
881 qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
882 addr_str);
883 i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
884 }
885 spin_unlock_irqrestore(&card->ip_lock, flags);
886 i += snprintf(buf + i, PAGE_SIZE - i, "\n");
887
888 return i;
889}
890
891static ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev,
892 struct device_attribute *attr, char *buf)
893{
894 struct qeth_card *card = dev_get_drvdata(dev);
895
896 if (!card)
897 return -EINVAL;
898
899 return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
900}
901
902static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto,
903 u8 *addr)
904{
905 if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
Frank Blaschka4a71df52008-02-15 09:19:42 +0100906 return -EINVAL;
907 }
908 return 0;
909}
910
911static ssize_t qeth_l3_dev_rxip_add_store(const char *buf, size_t count,
912 struct qeth_card *card, enum qeth_prot_versions proto)
913{
914 u8 addr[16] = {0, };
915 int rc;
916
Frank Blaschkac4949f02010-05-11 19:34:47 +0000917 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100918 rc = qeth_l3_parse_rxipe(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000919 if (!rc)
920 rc = qeth_l3_add_rxip(card, proto, addr);
921 mutex_unlock(&card->conf_mutex);
922 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100923}
924
925static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev,
926 struct device_attribute *attr, const char *buf, size_t count)
927{
928 struct qeth_card *card = dev_get_drvdata(dev);
929
930 if (!card)
931 return -EINVAL;
932
933 return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV4);
934}
935
936static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
937 qeth_l3_dev_rxip_add4_show,
938 qeth_l3_dev_rxip_add4_store);
939
940static ssize_t qeth_l3_dev_rxip_del_store(const char *buf, size_t count,
941 struct qeth_card *card, enum qeth_prot_versions proto)
942{
943 u8 addr[16];
944 int rc;
945
Frank Blaschkac4949f02010-05-11 19:34:47 +0000946 mutex_lock(&card->conf_mutex);
Frank Blaschka4a71df52008-02-15 09:19:42 +0100947 rc = qeth_l3_parse_rxipe(buf, proto, addr);
Frank Blaschkac4949f02010-05-11 19:34:47 +0000948 if (!rc)
949 qeth_l3_del_rxip(card, proto, addr);
950 mutex_unlock(&card->conf_mutex);
951 return rc ? rc : count;
Frank Blaschka4a71df52008-02-15 09:19:42 +0100952}
953
954static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev,
955 struct device_attribute *attr, const char *buf, size_t count)
956{
957 struct qeth_card *card = dev_get_drvdata(dev);
958
959 if (!card)
960 return -EINVAL;
961
962 return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV4);
963}
964
965static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL,
966 qeth_l3_dev_rxip_del4_store);
967
968static ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev,
969 struct device_attribute *attr, char *buf)
970{
971 struct qeth_card *card = dev_get_drvdata(dev);
972
973 if (!card)
974 return -EINVAL;
975
976 return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV6);
977}
978
979static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev,
980 struct device_attribute *attr, const char *buf, size_t count)
981{
982 struct qeth_card *card = dev_get_drvdata(dev);
983
984 if (!card)
985 return -EINVAL;
986
987 return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV6);
988}
989
990static QETH_DEVICE_ATTR(rxip_add6, add6, 0644,
991 qeth_l3_dev_rxip_add6_show,
992 qeth_l3_dev_rxip_add6_store);
993
994static ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev,
995 struct device_attribute *attr, const char *buf, size_t count)
996{
997 struct qeth_card *card = dev_get_drvdata(dev);
998
999 if (!card)
1000 return -EINVAL;
1001
1002 return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV6);
1003}
1004
1005static QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL,
1006 qeth_l3_dev_rxip_del6_store);
1007
1008static struct attribute *qeth_rxip_device_attrs[] = {
1009 &dev_attr_rxip_add4.attr,
1010 &dev_attr_rxip_del4.attr,
1011 &dev_attr_rxip_add6.attr,
1012 &dev_attr_rxip_del6.attr,
1013 NULL,
1014};
1015
1016static struct attribute_group qeth_device_rxip_group = {
1017 .name = "rxip",
1018 .attrs = qeth_rxip_device_attrs,
1019};
1020
1021int qeth_l3_create_device_attributes(struct device *dev)
1022{
1023 int ret;
1024
1025 ret = sysfs_create_group(&dev->kobj, &qeth_l3_device_attr_group);
1026 if (ret)
1027 return ret;
1028
1029 ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group);
1030 if (ret) {
1031 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1032 return ret;
1033 }
1034
1035 ret = sysfs_create_group(&dev->kobj, &qeth_device_vipa_group);
1036 if (ret) {
1037 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1038 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1039 return ret;
1040 }
1041
1042 ret = sysfs_create_group(&dev->kobj, &qeth_device_rxip_group);
1043 if (ret) {
1044 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1045 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1046 sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
1047 return ret;
1048 }
1049 return 0;
1050}
1051
1052void qeth_l3_remove_device_attributes(struct device *dev)
1053{
1054 sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
1055 sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
1056 sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
1057 sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
1058}