summaryrefslogtreecommitdiffstats
path: root/drivers/thunderbolt/switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thunderbolt/switch.c')
-rw-r--r--drivers/thunderbolt/switch.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 4b47e0999cda..1524edf42ee8 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -9,6 +9,9 @@
9 9
10#include "tb.h" 10#include "tb.h"
11 11
12/* Switch authorization from userspace is serialized by this lock */
13static DEFINE_MUTEX(switch_lock);
14
12/* port utility functions */ 15/* port utility functions */
13 16
14static const char *tb_port_type(struct tb_regs_port_header *port) 17static const char *tb_port_type(struct tb_regs_port_header *port)
@@ -310,6 +313,75 @@ static int tb_plug_events_active(struct tb_switch *sw, bool active)
310 sw->cap_plug_events + 1, 1); 313 sw->cap_plug_events + 1, 1);
311} 314}
312 315
316static ssize_t authorized_show(struct device *dev,
317 struct device_attribute *attr,
318 char *buf)
319{
320 struct tb_switch *sw = tb_to_switch(dev);
321
322 return sprintf(buf, "%u\n", sw->authorized);
323}
324
325static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
326{
327 int ret = -EINVAL;
328
329 if (mutex_lock_interruptible(&switch_lock))
330 return -ERESTARTSYS;
331
332 if (sw->authorized)
333 goto unlock;
334
335 switch (val) {
336 /* Approve switch */
337 case 1:
338 if (sw->key)
339 ret = tb_domain_approve_switch_key(sw->tb, sw);
340 else
341 ret = tb_domain_approve_switch(sw->tb, sw);
342 break;
343
344 /* Challenge switch */
345 case 2:
346 if (sw->key)
347 ret = tb_domain_challenge_switch_key(sw->tb, sw);
348 break;
349
350 default:
351 break;
352 }
353
354 if (!ret) {
355 sw->authorized = val;
356 /* Notify status change to the userspace */
357 kobject_uevent(&sw->dev.kobj, KOBJ_CHANGE);
358 }
359
360unlock:
361 mutex_unlock(&switch_lock);
362 return ret;
363}
364
365static ssize_t authorized_store(struct device *dev,
366 struct device_attribute *attr,
367 const char *buf, size_t count)
368{
369 struct tb_switch *sw = tb_to_switch(dev);
370 unsigned int val;
371 ssize_t ret;
372
373 ret = kstrtouint(buf, 0, &val);
374 if (ret)
375 return ret;
376 if (val > 2)
377 return -EINVAL;
378
379 ret = tb_switch_set_authorized(sw, val);
380
381 return ret ? ret : count;
382}
383static DEVICE_ATTR_RW(authorized);
384
313static ssize_t device_show(struct device *dev, struct device_attribute *attr, 385static ssize_t device_show(struct device *dev, struct device_attribute *attr,
314 char *buf) 386 char *buf)
315{ 387{
@@ -328,6 +400,54 @@ device_name_show(struct device *dev, struct device_attribute *attr, char *buf)
328} 400}
329static DEVICE_ATTR_RO(device_name); 401static DEVICE_ATTR_RO(device_name);
330 402
403static ssize_t key_show(struct device *dev, struct device_attribute *attr,
404 char *buf)
405{
406 struct tb_switch *sw = tb_to_switch(dev);
407 ssize_t ret;
408
409 if (mutex_lock_interruptible(&switch_lock))
410 return -ERESTARTSYS;
411
412 if (sw->key)
413 ret = sprintf(buf, "%*phN\n", TB_SWITCH_KEY_SIZE, sw->key);
414 else
415 ret = sprintf(buf, "\n");
416
417 mutex_unlock(&switch_lock);
418 return ret;
419}
420
421static ssize_t key_store(struct device *dev, struct device_attribute *attr,
422 const char *buf, size_t count)
423{
424 struct tb_switch *sw = tb_to_switch(dev);
425 u8 key[TB_SWITCH_KEY_SIZE];
426 ssize_t ret = count;
427
428 if (count < 64)
429 return -EINVAL;
430
431 if (hex2bin(key, buf, sizeof(key)))
432 return -EINVAL;
433
434 if (mutex_lock_interruptible(&switch_lock))
435 return -ERESTARTSYS;
436
437 if (sw->authorized) {
438 ret = -EBUSY;
439 } else {
440 kfree(sw->key);
441 sw->key = kmemdup(key, sizeof(key), GFP_KERNEL);
442 if (!sw->key)
443 ret = -ENOMEM;
444 }
445
446 mutex_unlock(&switch_lock);
447 return ret;
448}
449static DEVICE_ATTR_RW(key);
450
331static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, 451static ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
332 char *buf) 452 char *buf)
333{ 453{
@@ -356,15 +476,35 @@ static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr,
356static DEVICE_ATTR_RO(unique_id); 476static DEVICE_ATTR_RO(unique_id);
357 477
358static struct attribute *switch_attrs[] = { 478static struct attribute *switch_attrs[] = {
479 &dev_attr_authorized.attr,
359 &dev_attr_device.attr, 480 &dev_attr_device.attr,
360 &dev_attr_device_name.attr, 481 &dev_attr_device_name.attr,
482 &dev_attr_key.attr,
361 &dev_attr_vendor.attr, 483 &dev_attr_vendor.attr,
362 &dev_attr_vendor_name.attr, 484 &dev_attr_vendor_name.attr,
363 &dev_attr_unique_id.attr, 485 &dev_attr_unique_id.attr,
364 NULL, 486 NULL,
365}; 487};
366 488
489static umode_t switch_attr_is_visible(struct kobject *kobj,
490 struct attribute *attr, int n)
491{
492 struct device *dev = container_of(kobj, struct device, kobj);
493 struct tb_switch *sw = tb_to_switch(dev);
494
495 if (attr == &dev_attr_key.attr) {
496 if (tb_route(sw) &&
497 sw->tb->security_level == TB_SECURITY_SECURE &&
498 sw->security_level == TB_SECURITY_SECURE)
499 return attr->mode;
500 return 0;
501 }
502
503 return attr->mode;
504}
505
367static struct attribute_group switch_group = { 506static struct attribute_group switch_group = {
507 .is_visible = switch_attr_is_visible,
368 .attrs = switch_attrs, 508 .attrs = switch_attrs,
369}; 509};
370 510
@@ -384,6 +524,7 @@ static void tb_switch_release(struct device *dev)
384 kfree(sw->vendor_name); 524 kfree(sw->vendor_name);
385 kfree(sw->ports); 525 kfree(sw->ports);
386 kfree(sw->drom); 526 kfree(sw->drom);
527 kfree(sw->key);
387 kfree(sw); 528 kfree(sw);
388} 529}
389 530
@@ -490,6 +631,10 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
490 } 631 }
491 sw->cap_plug_events = cap; 632 sw->cap_plug_events = cap;
492 633
634 /* Root switch is always authorized */
635 if (!route)
636 sw->authorized = true;
637
493 device_initialize(&sw->dev); 638 device_initialize(&sw->dev);
494 sw->dev.parent = parent; 639 sw->dev.parent = parent;
495 sw->dev.bus = &tb_bus_type; 640 sw->dev.bus = &tb_bus_type;
@@ -754,3 +899,80 @@ void tb_switch_suspend(struct tb_switch *sw)
754 * effect? 899 * effect?
755 */ 900 */
756} 901}
902
903struct tb_sw_lookup {
904 struct tb *tb;
905 u8 link;
906 u8 depth;
907 const uuid_be *uuid;
908};
909
910static int tb_switch_match(struct device *dev, void *data)
911{
912 struct tb_switch *sw = tb_to_switch(dev);
913 struct tb_sw_lookup *lookup = data;
914
915 if (!sw)
916 return 0;
917 if (sw->tb != lookup->tb)
918 return 0;
919
920 if (lookup->uuid)
921 return !memcmp(sw->uuid, lookup->uuid, sizeof(*lookup->uuid));
922
923 /* Root switch is matched only by depth */
924 if (!lookup->depth)
925 return !sw->depth;
926
927 return sw->link == lookup->link && sw->depth == lookup->depth;
928}
929
930/**
931 * tb_switch_find_by_link_depth() - Find switch by link and depth
932 * @tb: Domain the switch belongs
933 * @link: Link number the switch is connected
934 * @depth: Depth of the switch in link
935 *
936 * Returned switch has reference count increased so the caller needs to
937 * call tb_switch_put() when done with the switch.
938 */
939struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link, u8 depth)
940{
941 struct tb_sw_lookup lookup;
942 struct device *dev;
943
944 memset(&lookup, 0, sizeof(lookup));
945 lookup.tb = tb;
946 lookup.link = link;
947 lookup.depth = depth;
948
949 dev = bus_find_device(&tb_bus_type, NULL, &lookup, tb_switch_match);
950 if (dev)
951 return tb_to_switch(dev);
952
953 return NULL;
954}
955
956/**
957 * tb_switch_find_by_link_depth() - Find switch by UUID
958 * @tb: Domain the switch belongs
959 * @uuid: UUID to look for
960 *
961 * Returned switch has reference count increased so the caller needs to
962 * call tb_switch_put() when done with the switch.
963 */
964struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_be *uuid)
965{
966 struct tb_sw_lookup lookup;
967 struct device *dev;
968
969 memset(&lookup, 0, sizeof(lookup));
970 lookup.tb = tb;
971 lookup.uuid = uuid;
972
973 dev = bus_find_device(&tb_bus_type, NULL, &lookup, tb_switch_match);
974 if (dev)
975 return tb_to_switch(dev);
976
977 return NULL;
978}