1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright IBM Corp. 2007 |
4 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
5 | * Frank Pavlic <fpavlic@de.ibm.com>, |
6 | * Thomas Spatzier <tspat@de.ibm.com>, |
7 | * Frank Blaschka <frank.blaschka@de.ibm.com> |
8 | */ |
9 | |
10 | #include <linux/slab.h> |
11 | #include <asm/ebcdic.h> |
12 | #include <linux/hashtable.h> |
13 | #include <linux/inet.h> |
14 | #include "qeth_l3.h" |
15 | |
16 | #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ |
17 | struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) |
18 | |
19 | static int qeth_l3_string_to_ipaddr(const char *buf, |
20 | enum qeth_prot_versions proto, u8 *addr) |
21 | { |
22 | const char *end; |
23 | |
24 | if ((proto == QETH_PROT_IPV4 && !in4_pton(src: buf, srclen: -1, dst: addr, delim: -1, end: &end)) || |
25 | (proto == QETH_PROT_IPV6 && !in6_pton(src: buf, srclen: -1, dst: addr, delim: -1, end: &end))) |
26 | return -EINVAL; |
27 | return 0; |
28 | } |
29 | |
30 | static ssize_t qeth_l3_dev_route_show(struct qeth_card *card, |
31 | struct qeth_routing_info *route, char *buf) |
32 | { |
33 | switch (route->type) { |
34 | case PRIMARY_ROUTER: |
35 | return sysfs_emit(buf, fmt: "%s\n" , "primary router" ); |
36 | case SECONDARY_ROUTER: |
37 | return sysfs_emit(buf, fmt: "%s\n" , "secondary router" ); |
38 | case MULTICAST_ROUTER: |
39 | if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) |
40 | return sysfs_emit(buf, fmt: "%s\n" , "multicast router+" ); |
41 | else |
42 | return sysfs_emit(buf, fmt: "%s\n" , "multicast router" ); |
43 | case PRIMARY_CONNECTOR: |
44 | if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) |
45 | return sysfs_emit(buf, fmt: "%s\n" , "primary connector+" ); |
46 | else |
47 | return sysfs_emit(buf, fmt: "%s\n" , "primary connector" ); |
48 | case SECONDARY_CONNECTOR: |
49 | if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) |
50 | return sysfs_emit(buf, fmt: "%s\n" , "secondary connector+" ); |
51 | else |
52 | return sysfs_emit(buf, fmt: "%s\n" , "secondary connector" ); |
53 | default: |
54 | return sysfs_emit(buf, fmt: "%s\n" , "no" ); |
55 | } |
56 | } |
57 | |
58 | static ssize_t qeth_l3_dev_route4_show(struct device *dev, |
59 | struct device_attribute *attr, char *buf) |
60 | { |
61 | struct qeth_card *card = dev_get_drvdata(dev); |
62 | |
63 | return qeth_l3_dev_route_show(card, route: &card->options.route4, buf); |
64 | } |
65 | |
66 | static ssize_t qeth_l3_dev_route_store(struct qeth_card *card, |
67 | struct qeth_routing_info *route, enum qeth_prot_versions prot, |
68 | const char *buf, size_t count) |
69 | { |
70 | enum qeth_routing_types old_route_type = route->type; |
71 | int rc = 0; |
72 | |
73 | mutex_lock(&card->conf_mutex); |
74 | if (sysfs_streq(s1: buf, s2: "no_router" )) { |
75 | route->type = NO_ROUTER; |
76 | } else if (sysfs_streq(s1: buf, s2: "primary_connector" )) { |
77 | route->type = PRIMARY_CONNECTOR; |
78 | } else if (sysfs_streq(s1: buf, s2: "secondary_connector" )) { |
79 | route->type = SECONDARY_CONNECTOR; |
80 | } else if (sysfs_streq(s1: buf, s2: "primary_router" )) { |
81 | route->type = PRIMARY_ROUTER; |
82 | } else if (sysfs_streq(s1: buf, s2: "secondary_router" )) { |
83 | route->type = SECONDARY_ROUTER; |
84 | } else if (sysfs_streq(s1: buf, s2: "multicast_router" )) { |
85 | route->type = MULTICAST_ROUTER; |
86 | } else { |
87 | rc = -EINVAL; |
88 | goto out; |
89 | } |
90 | if (qeth_card_hw_is_reachable(card) && |
91 | (old_route_type != route->type)) { |
92 | if (prot == QETH_PROT_IPV4) |
93 | rc = qeth_l3_setrouting_v4(card); |
94 | else if (prot == QETH_PROT_IPV6) |
95 | rc = qeth_l3_setrouting_v6(card); |
96 | } |
97 | out: |
98 | if (rc) |
99 | route->type = old_route_type; |
100 | mutex_unlock(lock: &card->conf_mutex); |
101 | return rc ? rc : count; |
102 | } |
103 | |
104 | static ssize_t qeth_l3_dev_route4_store(struct device *dev, |
105 | struct device_attribute *attr, const char *buf, size_t count) |
106 | { |
107 | struct qeth_card *card = dev_get_drvdata(dev); |
108 | |
109 | return qeth_l3_dev_route_store(card, route: &card->options.route4, |
110 | prot: QETH_PROT_IPV4, buf, count); |
111 | } |
112 | |
113 | static DEVICE_ATTR(route4, 0644, qeth_l3_dev_route4_show, |
114 | qeth_l3_dev_route4_store); |
115 | |
116 | static 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 | return qeth_l3_dev_route_show(card, route: &card->options.route6, buf); |
122 | } |
123 | |
124 | static ssize_t qeth_l3_dev_route6_store(struct device *dev, |
125 | struct device_attribute *attr, const char *buf, size_t count) |
126 | { |
127 | struct qeth_card *card = dev_get_drvdata(dev); |
128 | |
129 | return qeth_l3_dev_route_store(card, route: &card->options.route6, |
130 | prot: QETH_PROT_IPV6, buf, count); |
131 | } |
132 | |
133 | static DEVICE_ATTR(route6, 0644, qeth_l3_dev_route6_show, |
134 | qeth_l3_dev_route6_store); |
135 | |
136 | static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, |
137 | struct device_attribute *attr, char *buf) |
138 | { |
139 | struct qeth_card *card = dev_get_drvdata(dev); |
140 | |
141 | return sysfs_emit(buf, fmt: "%i\n" , card->options.sniffer ? 1 : 0); |
142 | } |
143 | |
144 | static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, |
145 | struct device_attribute *attr, const char *buf, size_t count) |
146 | { |
147 | struct qeth_card *card = dev_get_drvdata(dev); |
148 | int rc = 0; |
149 | unsigned long i; |
150 | |
151 | if (!IS_IQD(card)) |
152 | return -EPERM; |
153 | if (card->options.cq == QETH_CQ_ENABLED) |
154 | return -EPERM; |
155 | |
156 | mutex_lock(&card->conf_mutex); |
157 | if (card->state != CARD_STATE_DOWN) { |
158 | rc = -EPERM; |
159 | goto out; |
160 | } |
161 | |
162 | rc = kstrtoul(s: buf, base: 16, res: &i); |
163 | if (rc) { |
164 | rc = -EINVAL; |
165 | goto out; |
166 | } |
167 | switch (i) { |
168 | case 0: |
169 | card->options.sniffer = i; |
170 | break; |
171 | case 1: |
172 | qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); |
173 | if (card->ssqd.qdioac2 & CHSC_AC2_SNIFFER_AVAILABLE) { |
174 | card->options.sniffer = i; |
175 | qeth_resize_buffer_pool(card, QETH_IN_BUF_COUNT_MAX); |
176 | } else { |
177 | rc = -EPERM; |
178 | } |
179 | |
180 | break; |
181 | default: |
182 | rc = -EINVAL; |
183 | } |
184 | out: |
185 | mutex_unlock(lock: &card->conf_mutex); |
186 | return rc ? rc : count; |
187 | } |
188 | |
189 | static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, |
190 | qeth_l3_dev_sniffer_store); |
191 | |
192 | static ssize_t qeth_l3_dev_hsuid_show(struct device *dev, |
193 | struct device_attribute *attr, char *buf) |
194 | { |
195 | struct qeth_card *card = dev_get_drvdata(dev); |
196 | char tmp_hsuid[9]; |
197 | |
198 | if (!IS_IQD(card)) |
199 | return -EPERM; |
200 | |
201 | memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid)); |
202 | EBCASC(tmp_hsuid, 8); |
203 | return sysfs_emit(buf, fmt: "%s\n" , tmp_hsuid); |
204 | } |
205 | |
206 | static ssize_t qeth_l3_dev_hsuid_store(struct device *dev, |
207 | struct device_attribute *attr, const char *buf, size_t count) |
208 | { |
209 | struct qeth_card *card = dev_get_drvdata(dev); |
210 | int rc = 0; |
211 | char *tmp; |
212 | |
213 | if (!IS_IQD(card)) |
214 | return -EPERM; |
215 | |
216 | mutex_lock(&card->conf_mutex); |
217 | if (card->state != CARD_STATE_DOWN) { |
218 | rc = -EPERM; |
219 | goto out; |
220 | } |
221 | |
222 | if (card->options.sniffer) { |
223 | rc = -EPERM; |
224 | goto out; |
225 | } |
226 | |
227 | if (card->options.cq == QETH_CQ_NOTAVAILABLE) { |
228 | rc = -EPERM; |
229 | goto out; |
230 | } |
231 | |
232 | tmp = strsep((char **)&buf, "\n" ); |
233 | if (strlen(tmp) > 8) { |
234 | rc = -EINVAL; |
235 | goto out; |
236 | } |
237 | |
238 | if (card->options.hsuid[0]) |
239 | /* delete old ip address */ |
240 | qeth_l3_modify_hsuid(card, add: false); |
241 | |
242 | if (strlen(tmp) == 0) { |
243 | /* delete ip address only */ |
244 | card->options.hsuid[0] = '\0'; |
245 | memcpy(card->dev->perm_addr, card->options.hsuid, 9); |
246 | qeth_configure_cq(card, QETH_CQ_DISABLED); |
247 | goto out; |
248 | } |
249 | |
250 | if (qeth_configure_cq(card, QETH_CQ_ENABLED)) { |
251 | rc = -EPERM; |
252 | goto out; |
253 | } |
254 | |
255 | scnprintf(buf: card->options.hsuid, size: sizeof(card->options.hsuid), |
256 | fmt: "%-8s" , tmp); |
257 | ASCEBC(card->options.hsuid, 8); |
258 | memcpy(card->dev->perm_addr, card->options.hsuid, 9); |
259 | |
260 | rc = qeth_l3_modify_hsuid(card, add: true); |
261 | |
262 | out: |
263 | mutex_unlock(lock: &card->conf_mutex); |
264 | return rc ? rc : count; |
265 | } |
266 | |
267 | static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show, |
268 | qeth_l3_dev_hsuid_store); |
269 | |
270 | |
271 | static struct attribute *qeth_l3_device_attrs[] = { |
272 | &dev_attr_route4.attr, |
273 | &dev_attr_route6.attr, |
274 | &dev_attr_sniffer.attr, |
275 | &dev_attr_hsuid.attr, |
276 | NULL, |
277 | }; |
278 | |
279 | static const struct attribute_group qeth_l3_device_attr_group = { |
280 | .attrs = qeth_l3_device_attrs, |
281 | }; |
282 | |
283 | static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev, |
284 | struct device_attribute *attr, char *buf) |
285 | { |
286 | struct qeth_card *card = dev_get_drvdata(dev); |
287 | |
288 | return sysfs_emit(buf, fmt: "%u\n" , card->ipato.enabled ? 1 : 0); |
289 | } |
290 | |
291 | static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, |
292 | struct device_attribute *attr, const char *buf, size_t count) |
293 | { |
294 | struct qeth_card *card = dev_get_drvdata(dev); |
295 | bool enable; |
296 | int rc = 0; |
297 | |
298 | mutex_lock(&card->conf_mutex); |
299 | if (card->state != CARD_STATE_DOWN) { |
300 | rc = -EPERM; |
301 | goto out; |
302 | } |
303 | |
304 | mutex_lock(&card->ip_lock); |
305 | if (sysfs_streq(s1: buf, s2: "toggle" )) { |
306 | enable = !card->ipato.enabled; |
307 | } else if (kstrtobool(s: buf, res: &enable)) { |
308 | rc = -EINVAL; |
309 | goto unlock_ip; |
310 | } |
311 | |
312 | if (card->ipato.enabled != enable) { |
313 | card->ipato.enabled = enable; |
314 | qeth_l3_update_ipato(card); |
315 | } |
316 | |
317 | unlock_ip: |
318 | mutex_unlock(lock: &card->ip_lock); |
319 | out: |
320 | mutex_unlock(lock: &card->conf_mutex); |
321 | return rc ? rc : count; |
322 | } |
323 | |
324 | static QETH_DEVICE_ATTR(ipato_enable, enable, 0644, |
325 | qeth_l3_dev_ipato_enable_show, |
326 | qeth_l3_dev_ipato_enable_store); |
327 | |
328 | static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev, |
329 | struct device_attribute *attr, char *buf) |
330 | { |
331 | struct qeth_card *card = dev_get_drvdata(dev); |
332 | |
333 | return sysfs_emit(buf, fmt: "%u\n" , card->ipato.invert4 ? 1 : 0); |
334 | } |
335 | |
336 | static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, |
337 | struct device_attribute *attr, |
338 | const char *buf, size_t count) |
339 | { |
340 | struct qeth_card *card = dev_get_drvdata(dev); |
341 | bool invert; |
342 | int rc = 0; |
343 | |
344 | mutex_lock(&card->ip_lock); |
345 | if (sysfs_streq(s1: buf, s2: "toggle" )) { |
346 | invert = !card->ipato.invert4; |
347 | } else if (kstrtobool(s: buf, res: &invert)) { |
348 | rc = -EINVAL; |
349 | goto out; |
350 | } |
351 | |
352 | if (card->ipato.invert4 != invert) { |
353 | card->ipato.invert4 = invert; |
354 | qeth_l3_update_ipato(card); |
355 | } |
356 | |
357 | out: |
358 | mutex_unlock(lock: &card->ip_lock); |
359 | return rc ? rc : count; |
360 | } |
361 | |
362 | static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644, |
363 | qeth_l3_dev_ipato_invert4_show, |
364 | qeth_l3_dev_ipato_invert4_store); |
365 | |
366 | static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card, |
367 | enum qeth_prot_versions proto) |
368 | { |
369 | struct qeth_ipato_entry *ipatoe; |
370 | char addr_str[INET6_ADDRSTRLEN]; |
371 | int offset = 0; |
372 | |
373 | mutex_lock(&card->ip_lock); |
374 | list_for_each_entry(ipatoe, &card->ipato.entries, entry) { |
375 | if (ipatoe->proto != proto) |
376 | continue; |
377 | |
378 | qeth_l3_ipaddr_to_string(proto, addr: ipatoe->addr, buf: addr_str); |
379 | offset += sysfs_emit_at(buf, at: offset, fmt: "%s/%i\n" , |
380 | addr_str, ipatoe->mask_bits); |
381 | } |
382 | mutex_unlock(lock: &card->ip_lock); |
383 | |
384 | return offset ? offset : sysfs_emit(buf, fmt: "\n" ); |
385 | } |
386 | |
387 | static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev, |
388 | struct device_attribute *attr, char *buf) |
389 | { |
390 | struct qeth_card *card = dev_get_drvdata(dev); |
391 | |
392 | return qeth_l3_dev_ipato_add_show(buf, card, proto: QETH_PROT_IPV4); |
393 | } |
394 | |
395 | static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto, |
396 | u8 *addr, unsigned int *mask_bits) |
397 | { |
398 | char *sep; |
399 | int rc; |
400 | |
401 | /* Expected input pattern: %addr/%mask */ |
402 | sep = strnchr(buf, INET6_ADDRSTRLEN, '/'); |
403 | if (!sep) |
404 | return -EINVAL; |
405 | |
406 | /* Terminate the %addr sub-string, and parse it: */ |
407 | *sep = '\0'; |
408 | rc = qeth_l3_string_to_ipaddr(buf, proto, addr); |
409 | if (rc) |
410 | return rc; |
411 | |
412 | rc = kstrtouint(s: sep + 1, base: 10, res: mask_bits); |
413 | if (rc) |
414 | return rc; |
415 | |
416 | if (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128)) |
417 | return -EINVAL; |
418 | |
419 | return 0; |
420 | } |
421 | |
422 | static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count, |
423 | struct qeth_card *card, enum qeth_prot_versions proto) |
424 | { |
425 | struct qeth_ipato_entry *ipatoe; |
426 | unsigned int mask_bits; |
427 | u8 addr[16]; |
428 | int rc = 0; |
429 | |
430 | rc = qeth_l3_parse_ipatoe(buf, proto, addr, mask_bits: &mask_bits); |
431 | if (rc) |
432 | return rc; |
433 | |
434 | ipatoe = kzalloc(size: sizeof(struct qeth_ipato_entry), GFP_KERNEL); |
435 | if (!ipatoe) |
436 | return -ENOMEM; |
437 | |
438 | ipatoe->proto = proto; |
439 | memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4) ? 4 : 16); |
440 | ipatoe->mask_bits = mask_bits; |
441 | |
442 | rc = qeth_l3_add_ipato_entry(card, ipatoe); |
443 | if (rc) |
444 | kfree(objp: ipatoe); |
445 | |
446 | return rc ? rc : count; |
447 | } |
448 | |
449 | static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev, |
450 | struct device_attribute *attr, const char *buf, size_t count) |
451 | { |
452 | struct qeth_card *card = dev_get_drvdata(dev); |
453 | |
454 | return qeth_l3_dev_ipato_add_store(buf, count, card, proto: QETH_PROT_IPV4); |
455 | } |
456 | |
457 | static QETH_DEVICE_ATTR(ipato_add4, add4, 0644, |
458 | qeth_l3_dev_ipato_add4_show, |
459 | qeth_l3_dev_ipato_add4_store); |
460 | |
461 | static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count, |
462 | struct qeth_card *card, enum qeth_prot_versions proto) |
463 | { |
464 | unsigned int mask_bits; |
465 | u8 addr[16]; |
466 | int rc = 0; |
467 | |
468 | rc = qeth_l3_parse_ipatoe(buf, proto, addr, mask_bits: &mask_bits); |
469 | if (!rc) |
470 | rc = qeth_l3_del_ipato_entry(card, proto, addr, mask_bits); |
471 | return rc ? rc : count; |
472 | } |
473 | |
474 | static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev, |
475 | struct device_attribute *attr, const char *buf, size_t count) |
476 | { |
477 | struct qeth_card *card = dev_get_drvdata(dev); |
478 | |
479 | return qeth_l3_dev_ipato_del_store(buf, count, card, proto: QETH_PROT_IPV4); |
480 | } |
481 | |
482 | static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL, |
483 | qeth_l3_dev_ipato_del4_store); |
484 | |
485 | static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev, |
486 | struct device_attribute *attr, char *buf) |
487 | { |
488 | struct qeth_card *card = dev_get_drvdata(dev); |
489 | |
490 | return sysfs_emit(buf, fmt: "%u\n" , card->ipato.invert6 ? 1 : 0); |
491 | } |
492 | |
493 | static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, |
494 | struct device_attribute *attr, const char *buf, size_t count) |
495 | { |
496 | struct qeth_card *card = dev_get_drvdata(dev); |
497 | bool invert; |
498 | int rc = 0; |
499 | |
500 | mutex_lock(&card->ip_lock); |
501 | if (sysfs_streq(s1: buf, s2: "toggle" )) { |
502 | invert = !card->ipato.invert6; |
503 | } else if (kstrtobool(s: buf, res: &invert)) { |
504 | rc = -EINVAL; |
505 | goto out; |
506 | } |
507 | |
508 | if (card->ipato.invert6 != invert) { |
509 | card->ipato.invert6 = invert; |
510 | qeth_l3_update_ipato(card); |
511 | } |
512 | |
513 | out: |
514 | mutex_unlock(lock: &card->ip_lock); |
515 | return rc ? rc : count; |
516 | } |
517 | |
518 | static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644, |
519 | qeth_l3_dev_ipato_invert6_show, |
520 | qeth_l3_dev_ipato_invert6_store); |
521 | |
522 | |
523 | static ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev, |
524 | struct device_attribute *attr, char *buf) |
525 | { |
526 | struct qeth_card *card = dev_get_drvdata(dev); |
527 | |
528 | return qeth_l3_dev_ipato_add_show(buf, card, proto: QETH_PROT_IPV6); |
529 | } |
530 | |
531 | static ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev, |
532 | struct device_attribute *attr, const char *buf, size_t count) |
533 | { |
534 | struct qeth_card *card = dev_get_drvdata(dev); |
535 | |
536 | return qeth_l3_dev_ipato_add_store(buf, count, card, proto: QETH_PROT_IPV6); |
537 | } |
538 | |
539 | static QETH_DEVICE_ATTR(ipato_add6, add6, 0644, |
540 | qeth_l3_dev_ipato_add6_show, |
541 | qeth_l3_dev_ipato_add6_store); |
542 | |
543 | static ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev, |
544 | struct device_attribute *attr, const char *buf, size_t count) |
545 | { |
546 | struct qeth_card *card = dev_get_drvdata(dev); |
547 | |
548 | return qeth_l3_dev_ipato_del_store(buf, count, card, proto: QETH_PROT_IPV6); |
549 | } |
550 | |
551 | static QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL, |
552 | qeth_l3_dev_ipato_del6_store); |
553 | |
554 | static struct attribute *qeth_ipato_device_attrs[] = { |
555 | &dev_attr_ipato_enable.attr, |
556 | &dev_attr_ipato_invert4.attr, |
557 | &dev_attr_ipato_add4.attr, |
558 | &dev_attr_ipato_del4.attr, |
559 | &dev_attr_ipato_invert6.attr, |
560 | &dev_attr_ipato_add6.attr, |
561 | &dev_attr_ipato_del6.attr, |
562 | NULL, |
563 | }; |
564 | |
565 | static const struct attribute_group qeth_device_ipato_group = { |
566 | .name = "ipa_takeover" , |
567 | .attrs = qeth_ipato_device_attrs, |
568 | }; |
569 | |
570 | static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf, |
571 | enum qeth_prot_versions proto, |
572 | enum qeth_ip_types type) |
573 | { |
574 | struct qeth_card *card = dev_get_drvdata(dev); |
575 | char addr_str[INET6_ADDRSTRLEN]; |
576 | struct qeth_ipaddr *ipaddr; |
577 | int offset = 0; |
578 | int i; |
579 | |
580 | mutex_lock(&card->ip_lock); |
581 | hash_for_each(card->ip_htable, i, ipaddr, hnode) { |
582 | if (ipaddr->proto != proto || ipaddr->type != type) |
583 | continue; |
584 | |
585 | qeth_l3_ipaddr_to_string(proto, addr: (u8 *)&ipaddr->u, buf: addr_str); |
586 | offset += sysfs_emit_at(buf, at: offset, fmt: "%s\n" , addr_str); |
587 | } |
588 | mutex_unlock(lock: &card->ip_lock); |
589 | |
590 | return offset ? offset : sysfs_emit(buf, fmt: "\n" ); |
591 | } |
592 | |
593 | static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev, |
594 | struct device_attribute *attr, |
595 | char *buf) |
596 | { |
597 | return qeth_l3_dev_ip_add_show(dev, buf, proto: QETH_PROT_IPV4, |
598 | type: QETH_IP_TYPE_VIPA); |
599 | } |
600 | |
601 | static ssize_t qeth_l3_vipa_store(struct device *dev, const char *buf, bool add, |
602 | size_t count, enum qeth_prot_versions proto) |
603 | { |
604 | struct qeth_card *card = dev_get_drvdata(dev); |
605 | u8 addr[16] = {0, }; |
606 | int rc; |
607 | |
608 | rc = qeth_l3_string_to_ipaddr(buf, proto, addr); |
609 | if (!rc) |
610 | rc = qeth_l3_modify_rxip_vipa(card, add, ip: addr, |
611 | type: QETH_IP_TYPE_VIPA, proto); |
612 | return rc ? rc : count; |
613 | } |
614 | |
615 | static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev, |
616 | struct device_attribute *attr, const char *buf, size_t count) |
617 | { |
618 | return qeth_l3_vipa_store(dev, buf, add: true, count, proto: QETH_PROT_IPV4); |
619 | } |
620 | |
621 | static QETH_DEVICE_ATTR(vipa_add4, add4, 0644, |
622 | qeth_l3_dev_vipa_add4_show, |
623 | qeth_l3_dev_vipa_add4_store); |
624 | |
625 | static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev, |
626 | struct device_attribute *attr, const char *buf, size_t count) |
627 | { |
628 | return qeth_l3_vipa_store(dev, buf, add: false, count, proto: QETH_PROT_IPV4); |
629 | } |
630 | |
631 | static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL, |
632 | qeth_l3_dev_vipa_del4_store); |
633 | |
634 | static ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev, |
635 | struct device_attribute *attr, |
636 | char *buf) |
637 | { |
638 | return qeth_l3_dev_ip_add_show(dev, buf, proto: QETH_PROT_IPV6, |
639 | type: QETH_IP_TYPE_VIPA); |
640 | } |
641 | |
642 | static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev, |
643 | struct device_attribute *attr, const char *buf, size_t count) |
644 | { |
645 | return qeth_l3_vipa_store(dev, buf, add: true, count, proto: QETH_PROT_IPV6); |
646 | } |
647 | |
648 | static QETH_DEVICE_ATTR(vipa_add6, add6, 0644, |
649 | qeth_l3_dev_vipa_add6_show, |
650 | qeth_l3_dev_vipa_add6_store); |
651 | |
652 | static ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev, |
653 | struct device_attribute *attr, const char *buf, size_t count) |
654 | { |
655 | return qeth_l3_vipa_store(dev, buf, add: false, count, proto: QETH_PROT_IPV6); |
656 | } |
657 | |
658 | static QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL, |
659 | qeth_l3_dev_vipa_del6_store); |
660 | |
661 | static struct attribute *qeth_vipa_device_attrs[] = { |
662 | &dev_attr_vipa_add4.attr, |
663 | &dev_attr_vipa_del4.attr, |
664 | &dev_attr_vipa_add6.attr, |
665 | &dev_attr_vipa_del6.attr, |
666 | NULL, |
667 | }; |
668 | |
669 | static const struct attribute_group qeth_device_vipa_group = { |
670 | .name = "vipa" , |
671 | .attrs = qeth_vipa_device_attrs, |
672 | }; |
673 | |
674 | static ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev, |
675 | struct device_attribute *attr, |
676 | char *buf) |
677 | { |
678 | return qeth_l3_dev_ip_add_show(dev, buf, proto: QETH_PROT_IPV4, |
679 | type: QETH_IP_TYPE_RXIP); |
680 | } |
681 | |
682 | static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto, |
683 | u8 *addr) |
684 | { |
685 | __be32 ipv4_addr; |
686 | struct in6_addr ipv6_addr; |
687 | |
688 | if (qeth_l3_string_to_ipaddr(buf, proto, addr)) { |
689 | return -EINVAL; |
690 | } |
691 | if (proto == QETH_PROT_IPV4) { |
692 | memcpy(&ipv4_addr, addr, sizeof(ipv4_addr)); |
693 | if (ipv4_is_multicast(addr: ipv4_addr)) { |
694 | QETH_DBF_MESSAGE(2, "multicast rxip not supported.\n" ); |
695 | return -EINVAL; |
696 | } |
697 | } else if (proto == QETH_PROT_IPV6) { |
698 | memcpy(&ipv6_addr, addr, sizeof(ipv6_addr)); |
699 | if (ipv6_addr_is_multicast(addr: &ipv6_addr)) { |
700 | QETH_DBF_MESSAGE(2, "multicast rxip not supported.\n" ); |
701 | return -EINVAL; |
702 | } |
703 | } |
704 | |
705 | return 0; |
706 | } |
707 | |
708 | static ssize_t qeth_l3_rxip_store(struct device *dev, const char *buf, bool add, |
709 | size_t count, enum qeth_prot_versions proto) |
710 | { |
711 | struct qeth_card *card = dev_get_drvdata(dev); |
712 | u8 addr[16] = {0, }; |
713 | int rc; |
714 | |
715 | rc = qeth_l3_parse_rxipe(buf, proto, addr); |
716 | if (!rc) |
717 | rc = qeth_l3_modify_rxip_vipa(card, add, ip: addr, |
718 | type: QETH_IP_TYPE_RXIP, proto); |
719 | return rc ? rc : count; |
720 | } |
721 | |
722 | static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev, |
723 | struct device_attribute *attr, const char *buf, size_t count) |
724 | { |
725 | return qeth_l3_rxip_store(dev, buf, add: true, count, proto: QETH_PROT_IPV4); |
726 | } |
727 | |
728 | static QETH_DEVICE_ATTR(rxip_add4, add4, 0644, |
729 | qeth_l3_dev_rxip_add4_show, |
730 | qeth_l3_dev_rxip_add4_store); |
731 | |
732 | static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev, |
733 | struct device_attribute *attr, const char *buf, size_t count) |
734 | { |
735 | return qeth_l3_rxip_store(dev, buf, add: false, count, proto: QETH_PROT_IPV4); |
736 | } |
737 | |
738 | static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL, |
739 | qeth_l3_dev_rxip_del4_store); |
740 | |
741 | static ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev, |
742 | struct device_attribute *attr, |
743 | char *buf) |
744 | { |
745 | return qeth_l3_dev_ip_add_show(dev, buf, proto: QETH_PROT_IPV6, |
746 | type: QETH_IP_TYPE_RXIP); |
747 | } |
748 | |
749 | static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev, |
750 | struct device_attribute *attr, const char *buf, size_t count) |
751 | { |
752 | return qeth_l3_rxip_store(dev, buf, add: true, count, proto: QETH_PROT_IPV6); |
753 | } |
754 | |
755 | static QETH_DEVICE_ATTR(rxip_add6, add6, 0644, |
756 | qeth_l3_dev_rxip_add6_show, |
757 | qeth_l3_dev_rxip_add6_store); |
758 | |
759 | static ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev, |
760 | struct device_attribute *attr, const char *buf, size_t count) |
761 | { |
762 | return qeth_l3_rxip_store(dev, buf, add: false, count, proto: QETH_PROT_IPV6); |
763 | } |
764 | |
765 | static QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL, |
766 | qeth_l3_dev_rxip_del6_store); |
767 | |
768 | static struct attribute *qeth_rxip_device_attrs[] = { |
769 | &dev_attr_rxip_add4.attr, |
770 | &dev_attr_rxip_del4.attr, |
771 | &dev_attr_rxip_add6.attr, |
772 | &dev_attr_rxip_del6.attr, |
773 | NULL, |
774 | }; |
775 | |
776 | static const struct attribute_group qeth_device_rxip_group = { |
777 | .name = "rxip" , |
778 | .attrs = qeth_rxip_device_attrs, |
779 | }; |
780 | |
781 | const struct attribute_group *qeth_l3_attr_groups[] = { |
782 | &qeth_l3_device_attr_group, |
783 | &qeth_device_ipato_group, |
784 | &qeth_device_vipa_group, |
785 | &qeth_device_rxip_group, |
786 | NULL, |
787 | }; |
788 | |