Signed-off-by: Phoebe Buckheister <phoebe.buckheis...@itwm.fraunhofer.de>
---
 net/mac802154/llsec.c |  123 ++++++++++++++++++++++++++++++++++++++++++++++++-
 net/mac802154/llsec.h |    5 ++
 2 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c
index 0b2319b..77966c1 100644
--- a/net/mac802154/llsec.c
+++ b/net/mac802154/llsec.c
@@ -30,6 +30,8 @@ static void llsec_key_put(struct mac802154_llsec_key *key);
 static bool llsec_key_id_equal(const struct ieee802154_llsec_key_id *a,
                               const struct ieee802154_llsec_key_id *b);
 
+static void llsec_dev_free(struct mac802154_llsec_device *dev);
+
 void mac802154_llsec_init(struct mac802154_llsec *sec)
 {
        memset(sec, 0, sizeof(*sec));
@@ -63,7 +65,7 @@ void mac802154_llsec_destroy(struct mac802154_llsec *sec)
 
                mdev = container_of(dev, struct mac802154_llsec_device, dev);
                list_del(&dev->list);
-               kfree(mdev);
+               llsec_dev_free(mdev);
        }
 
        list_for_each_entry_safe(key, kn, &sec->table.keys, list) {
@@ -311,3 +313,122 @@ int mac802154_llsec_key_del(struct mac802154_llsec *sec,
 
        return -ENOENT;
 }
+
+
+
+static bool llsec_dev_use_shortaddr(__le16 short_addr)
+{
+       return short_addr != cpu_to_le16(IEEE802154_ADDR_UNDEF) &&
+               short_addr != cpu_to_le16(0xffff);
+}
+
+static u32 llsec_dev_hash_short(__le16 short_addr, __le16 pan_id)
+{
+       return ((__force u16) short_addr) << 16 | (__force u16) pan_id;
+}
+
+static u64 llsec_dev_hash_long(__le64 hwaddr)
+{
+       return (__force u64) hwaddr;
+}
+
+static struct mac802154_llsec_device*
+llsec_dev_find_short(struct mac802154_llsec *sec, __le16 short_addr,
+                    __le16 pan_id)
+{
+       struct mac802154_llsec_device *dev;
+       u32 key = llsec_dev_hash_short(short_addr, pan_id);
+
+       hash_for_each_possible_rcu(sec->devices_short, dev, bucket_s, key) {
+               if (dev->dev.short_addr != short_addr ||
+                   dev->dev.pan_id == pan_id)
+                       continue;
+
+               return dev;
+       }
+
+       return NULL;
+}
+
+static struct mac802154_llsec_device*
+llsec_dev_find_long(struct mac802154_llsec *sec, __le64 hwaddr)
+{
+       struct mac802154_llsec_device *dev;
+       u64 key = llsec_dev_hash_long(hwaddr);
+
+       hash_for_each_possible_rcu(sec->devices_hw, dev, bucket_hw, key) {
+               if (dev->dev.hwaddr != hwaddr)
+                       continue;
+
+               return dev;
+       }
+
+       return NULL;
+}
+
+static void llsec_dev_free(struct mac802154_llsec_device *dev)
+{
+       struct ieee802154_llsec_device_key *pos;
+       struct mac802154_llsec_device_key *devkey;
+
+       list_for_each_entry(pos, &dev->dev.keys, list) {
+               devkey = container_of(pos, struct mac802154_llsec_device_key,
+                                     devkey);
+
+               kfree_rcu(devkey, rcu);
+       }
+
+       kfree(dev);
+}
+
+int mac802154_llsec_dev_add(struct mac802154_llsec *sec,
+                           const struct ieee802154_llsec_device *dev)
+{
+       struct mac802154_llsec_device *entry;
+       u32 skey = llsec_dev_hash_short(dev->short_addr, dev->pan_id);
+       u64 hwkey = llsec_dev_hash_long(dev->hwaddr);
+
+       BUILD_BUG_ON(sizeof(hwkey) != IEEE802154_ADDR_LEN);
+
+       if ((llsec_dev_use_shortaddr(dev->short_addr) &&
+            llsec_dev_find_short(sec, dev->short_addr, dev->pan_id)) ||
+           llsec_dev_find_long(sec, dev->hwaddr))
+               return -EEXIST;
+
+       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       entry->dev = *dev;
+       spin_lock_init(&entry->lock);
+       INIT_LIST_HEAD(&entry->dev.keys);
+
+       if (llsec_dev_use_shortaddr(dev->short_addr))
+               hash_add_rcu(sec->devices_short, &entry->bucket_s, skey);
+       else
+               INIT_HLIST_NODE(&entry->bucket_s);
+
+       hash_add_rcu(sec->devices_hw, &entry->bucket_hw, hwkey);
+
+       return 0;
+}
+
+static void llsec_dev_free_rcu(struct rcu_head *rcu)
+{
+       llsec_dev_free(container_of(rcu, struct mac802154_llsec_device, rcu));
+}
+
+int mac802154_llsec_dev_del(struct mac802154_llsec *sec, __le64 device_addr)
+{
+       struct mac802154_llsec_device *pos;
+
+       pos = llsec_dev_find_long(sec, device_addr);
+       if (!pos)
+               return -ENOENT;
+
+       hash_del_rcu(&pos->bucket_s);
+       hash_del_rcu(&pos->bucket_hw);
+       call_rcu(&pos->rcu, llsec_dev_free_rcu);
+
+       return 0;
+}
diff --git a/net/mac802154/llsec.h b/net/mac802154/llsec.h
index 47e23a3..087a164 100644
--- a/net/mac802154/llsec.h
+++ b/net/mac802154/llsec.h
@@ -89,4 +89,9 @@ int mac802154_llsec_key_add(struct mac802154_llsec *sec,
 int mac802154_llsec_key_del(struct mac802154_llsec *sec,
                            const struct ieee802154_llsec_key_id *key);
 
+int mac802154_llsec_dev_add(struct mac802154_llsec *sec,
+                           const struct ieee802154_llsec_device *dev);
+int mac802154_llsec_dev_del(struct mac802154_llsec *sec,
+                           __le64 device_addr);
+
 #endif /* MAC802154_LLSEC_H */
-- 
1.7.9.5


------------------------------------------------------------------------------
Is your legacy SCM system holding you back? Join Perforce May 7 to find out:
&#149; 3 signs your SCM is hindering your productivity
&#149; Requirements for releasing software faster
&#149; Expert tips and advice for migrating your SCM now
http://p.sf.net/sfu/perforce
_______________________________________________
Linux-zigbee-devel mailing list
Linux-zigbee-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel

Reply via email to