summaryrefslogtreecommitdiffstats
path: root/kernel/net/atm/addr.c
diff options
context:
space:
mode:
authorYunhong Jiang <yunhong.jiang@intel.com>2015-08-04 12:17:53 -0700
committerYunhong Jiang <yunhong.jiang@intel.com>2015-08-04 15:44:42 -0700
commit9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (patch)
tree1c9cafbcd35f783a87880a10f85d1a060db1a563 /kernel/net/atm/addr.c
parent98260f3884f4a202f9ca5eabed40b1354c489b29 (diff)
Add the rt linux 4.1.3-rt3 as base
Import the rt linux 4.1.3-rt3 as OPNFV kvm base. It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and the base is: commit 0917f823c59692d751951bf5ea699a2d1e2f26a2 Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Date: Sat Jul 25 12:13:34 2015 +0200 Prepare v4.1.3-rt3 Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> We lose all the git history this way and it's not good. We should apply another opnfv project repo in future. Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423 Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Diffstat (limited to 'kernel/net/atm/addr.c')
-rw-r--r--kernel/net/atm/addr.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/kernel/net/atm/addr.c b/kernel/net/atm/addr.c
new file mode 100644
index 000000000..dcda35c66
--- /dev/null
+++ b/kernel/net/atm/addr.c
@@ -0,0 +1,161 @@
+/* net/atm/addr.c - Local ATM address registry */
+
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
+
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "signaling.h"
+#include "addr.h"
+
+static int check_addr(const struct sockaddr_atmsvc *addr)
+{
+ int i;
+
+ if (addr->sas_family != AF_ATMSVC)
+ return -EAFNOSUPPORT;
+ if (!*addr->sas_addr.pub)
+ return *addr->sas_addr.prv ? 0 : -EINVAL;
+ for (i = 1; i < ATM_E164_LEN + 1; i++) /* make sure it's \0-terminated */
+ if (!addr->sas_addr.pub[i])
+ return 0;
+ return -EINVAL;
+}
+
+static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b)
+{
+ if (*a->sas_addr.prv)
+ if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
+ return 0;
+ if (!*a->sas_addr.pub)
+ return !*b->sas_addr.pub;
+ if (!*b->sas_addr.pub)
+ return 0;
+ return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
+}
+
+static void notify_sigd(const struct atm_dev *dev)
+{
+ struct sockaddr_atmpvc pvc;
+
+ pvc.sap_addr.itf = dev->number;
+ sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
+}
+
+void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype)
+{
+ unsigned long flags;
+ struct atm_dev_addr *this, *p;
+ struct list_head *head;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (atype == ATM_ADDR_LECS)
+ head = &dev->lecs;
+ else
+ head = &dev->local;
+ list_for_each_entry_safe(this, p, head, entry) {
+ list_del(&this->entry);
+ kfree(this);
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+ if (head == &dev->local)
+ notify_sigd(dev);
+}
+
+int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
+ enum atm_addr_type_t atype)
+{
+ unsigned long flags;
+ struct atm_dev_addr *this;
+ struct list_head *head;
+ int error;
+
+ error = check_addr(addr);
+ if (error)
+ return error;
+ spin_lock_irqsave(&dev->lock, flags);
+ if (atype == ATM_ADDR_LECS)
+ head = &dev->lecs;
+ else
+ head = &dev->local;
+ list_for_each_entry(this, head, entry) {
+ if (identical(&this->addr, addr)) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -EEXIST;
+ }
+ }
+ this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
+ if (!this) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -ENOMEM;
+ }
+ this->addr = *addr;
+ list_add(&this->entry, head);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ if (head == &dev->local)
+ notify_sigd(dev);
+ return 0;
+}
+
+int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
+ enum atm_addr_type_t atype)
+{
+ unsigned long flags;
+ struct atm_dev_addr *this;
+ struct list_head *head;
+ int error;
+
+ error = check_addr(addr);
+ if (error)
+ return error;
+ spin_lock_irqsave(&dev->lock, flags);
+ if (atype == ATM_ADDR_LECS)
+ head = &dev->lecs;
+ else
+ head = &dev->local;
+ list_for_each_entry(this, head, entry) {
+ if (identical(&this->addr, addr)) {
+ list_del(&this->entry);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ kfree(this);
+ if (head == &dev->local)
+ notify_sigd(dev);
+ return 0;
+ }
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -ENOENT;
+}
+
+int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
+ size_t size, enum atm_addr_type_t atype)
+{
+ unsigned long flags;
+ struct atm_dev_addr *this;
+ struct list_head *head;
+ int total = 0, error;
+ struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (atype == ATM_ADDR_LECS)
+ head = &dev->lecs;
+ else
+ head = &dev->local;
+ list_for_each_entry(this, head, entry)
+ total += sizeof(struct sockaddr_atmsvc);
+ tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
+ if (!tmp_buf) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -ENOMEM;
+ }
+ list_for_each_entry(this, head, entry)
+ memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
+ spin_unlock_irqrestore(&dev->lock, flags);
+ error = total > size ? -E2BIG : total;
+ if (copy_to_user(buf, tmp_buf, total < size ? total : size))
+ error = -EFAULT;
+ kfree(tmp_buf);
+ return error;
+}