Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
addr.c
Go to the documentation of this file.
1 /* net/atm/addr.c - Local ATM address registry */
2 
3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
4 
5 #include <linux/atm.h>
6 #include <linux/atmdev.h>
7 #include <linux/slab.h>
8 #include <linux/uaccess.h>
9 
10 #include "signaling.h"
11 #include "addr.h"
12 
13 static int check_addr(const struct sockaddr_atmsvc *addr)
14 {
15  int i;
16 
17  if (addr->sas_family != AF_ATMSVC)
18  return -EAFNOSUPPORT;
19  if (!*addr->sas_addr.pub)
20  return *addr->sas_addr.prv ? 0 : -EINVAL;
21  for (i = 1; i < ATM_E164_LEN + 1; i++) /* make sure it's \0-terminated */
22  if (!addr->sas_addr.pub[i])
23  return 0;
24  return -EINVAL;
25 }
26 
27 static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b)
28 {
29  if (*a->sas_addr.prv)
30  if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
31  return 0;
32  if (!*a->sas_addr.pub)
33  return !*b->sas_addr.pub;
34  if (!*b->sas_addr.pub)
35  return 0;
36  return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
37 }
38 
39 static void notify_sigd(const struct atm_dev *dev)
40 {
41  struct sockaddr_atmpvc pvc;
42 
43  pvc.sap_addr.itf = dev->number;
45 }
46 
47 void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype)
48 {
49  unsigned long flags;
50  struct atm_dev_addr *this, *p;
51  struct list_head *head;
52 
53  spin_lock_irqsave(&dev->lock, flags);
54  if (atype == ATM_ADDR_LECS)
55  head = &dev->lecs;
56  else
57  head = &dev->local;
58  list_for_each_entry_safe(this, p, head, entry) {
59  list_del(&this->entry);
60  kfree(this);
61  }
62  spin_unlock_irqrestore(&dev->lock, flags);
63  if (head == &dev->local)
64  notify_sigd(dev);
65 }
66 
67 int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
68  enum atm_addr_type_t atype)
69 {
70  unsigned long flags;
71  struct atm_dev_addr *this;
72  struct list_head *head;
73  int error;
74 
75  error = check_addr(addr);
76  if (error)
77  return error;
78  spin_lock_irqsave(&dev->lock, flags);
79  if (atype == ATM_ADDR_LECS)
80  head = &dev->lecs;
81  else
82  head = &dev->local;
83  list_for_each_entry(this, head, entry) {
84  if (identical(&this->addr, addr)) {
85  spin_unlock_irqrestore(&dev->lock, flags);
86  return -EEXIST;
87  }
88  }
89  this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
90  if (!this) {
91  spin_unlock_irqrestore(&dev->lock, flags);
92  return -ENOMEM;
93  }
94  this->addr = *addr;
95  list_add(&this->entry, head);
96  spin_unlock_irqrestore(&dev->lock, flags);
97  if (head == &dev->local)
98  notify_sigd(dev);
99  return 0;
100 }
101 
102 int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
103  enum atm_addr_type_t atype)
104 {
105  unsigned long flags;
106  struct atm_dev_addr *this;
107  struct list_head *head;
108  int error;
109 
110  error = check_addr(addr);
111  if (error)
112  return error;
113  spin_lock_irqsave(&dev->lock, flags);
114  if (atype == ATM_ADDR_LECS)
115  head = &dev->lecs;
116  else
117  head = &dev->local;
118  list_for_each_entry(this, head, entry) {
119  if (identical(&this->addr, addr)) {
120  list_del(&this->entry);
121  spin_unlock_irqrestore(&dev->lock, flags);
122  kfree(this);
123  if (head == &dev->local)
124  notify_sigd(dev);
125  return 0;
126  }
127  }
128  spin_unlock_irqrestore(&dev->lock, flags);
129  return -ENOENT;
130 }
131 
132 int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
133  size_t size, enum atm_addr_type_t atype)
134 {
135  unsigned long flags;
136  struct atm_dev_addr *this;
137  struct list_head *head;
138  int total = 0, error;
139  struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
140 
141  spin_lock_irqsave(&dev->lock, flags);
142  if (atype == ATM_ADDR_LECS)
143  head = &dev->lecs;
144  else
145  head = &dev->local;
146  list_for_each_entry(this, head, entry)
147  total += sizeof(struct sockaddr_atmsvc);
148  tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
149  if (!tmp_buf) {
150  spin_unlock_irqrestore(&dev->lock, flags);
151  return -ENOMEM;
152  }
153  list_for_each_entry(this, head, entry)
154  memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
155  spin_unlock_irqrestore(&dev->lock, flags);
156  error = total > size ? -E2BIG : total;
157  if (copy_to_user(buf, tmp_buf, total < size ? total : size))
158  error = -EFAULT;
159  kfree(tmp_buf);
160  return error;
161 }