1 /* net/atm/addr.c - Local ATM address registry */
2 
3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
4 
5 
6 #include <linux/atm.h>
7 #include <linux/atmdev.h>
8 #include <linux/sched.h>
9 #include <asm/uaccess.h>
10 
11 #include "signaling.h"
12 #include "addr.h"
13 
14 
check_addr(struct sockaddr_atmsvc * addr)15 static int check_addr(struct sockaddr_atmsvc *addr)
16 {
17 	int i;
18 
19 	if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
20 	if (!*addr->sas_addr.pub)
21 		return *addr->sas_addr.prv ? 0 : -EINVAL;
22 	for (i = 1; i < ATM_E164_LEN+1; i++) /* make sure it's \0-terminated */
23 		if (!addr->sas_addr.pub[i]) return 0;
24 	return -EINVAL;
25 }
26 
27 
identical(struct sockaddr_atmsvc * a,struct sockaddr_atmsvc * b)28 static int identical(struct sockaddr_atmsvc *a,struct sockaddr_atmsvc *b)
29 {
30 	if (*a->sas_addr.prv)
31 		if (memcmp(a->sas_addr.prv,b->sas_addr.prv,ATM_ESA_LEN))
32 			return 0;
33 	if (!*a->sas_addr.pub) return !*b->sas_addr.pub;
34 	if (!*b->sas_addr.pub) return 0;
35 	return !strcmp(a->sas_addr.pub,b->sas_addr.pub);
36 }
37 
38 
notify_sigd(struct atm_dev * dev)39 static void notify_sigd(struct atm_dev *dev)
40 {
41 	struct sockaddr_atmpvc pvc;
42 
43 	pvc.sap_addr.itf = dev->number;
44 	sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL);
45 }
46 
47 
atm_reset_addr(struct atm_dev * dev)48 void atm_reset_addr(struct atm_dev *dev)
49 {
50 	unsigned long flags;
51 	struct atm_dev_addr *this;
52 
53 	spin_lock_irqsave(&dev->lock, flags);
54 	while (dev->local) {
55 		this = dev->local;
56 		dev->local = this->next;
57 		kfree(this);
58 	}
59 	spin_unlock_irqrestore(&dev->lock, flags);
60 	notify_sigd(dev);
61 }
62 
63 
atm_add_addr(struct atm_dev * dev,struct sockaddr_atmsvc * addr)64 int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
65 {
66 	unsigned long flags;
67 	struct atm_dev_addr **walk;
68 	int error;
69 
70 	error = check_addr(addr);
71 	if (error)
72 		return error;
73 	spin_lock_irqsave(&dev->lock, flags);
74 	for (walk = &dev->local; *walk; walk = &(*walk)->next)
75 		if (identical(&(*walk)->addr,addr)) {
76 			spin_unlock_irqrestore(&dev->lock, flags);
77 			return -EEXIST;
78 		}
79 	*walk = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
80 	if (!*walk) {
81 		spin_unlock_irqrestore(&dev->lock, flags);
82 		return -ENOMEM;
83 	}
84 	(*walk)->addr = *addr;
85 	(*walk)->next = NULL;
86 	spin_unlock_irqrestore(&dev->lock, flags);
87 	notify_sigd(dev);
88 	return 0;
89 }
90 
91 
atm_del_addr(struct atm_dev * dev,struct sockaddr_atmsvc * addr)92 int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
93 {
94 	unsigned long flags;
95 	struct atm_dev_addr **walk,*this;
96 	int error;
97 
98 	error = check_addr(addr);
99 	if (error)
100 		return error;
101 	spin_lock_irqsave(&dev->lock, flags);
102 	for (walk = &dev->local; *walk; walk = &(*walk)->next)
103 		if (identical(&(*walk)->addr,addr)) break;
104 	if (!*walk) {
105 		spin_unlock_irqrestore(&dev->lock, flags);
106 		return -ENOENT;
107 	}
108 	this = *walk;
109 	*walk = this->next;
110 	kfree(this);
111 	spin_unlock_irqrestore(&dev->lock, flags);
112 	notify_sigd(dev);
113 	return 0;
114 }
115 
116 
atm_get_addr(struct atm_dev * dev,struct sockaddr_atmsvc * u_buf,size_t size)117 int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,size_t size)
118 {
119 	unsigned long flags;
120 	struct atm_dev_addr *walk;
121 	int total = 0, error;
122 	struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
123 
124 
125 	spin_lock_irqsave(&dev->lock, flags);
126 	for (walk = dev->local; walk; walk = walk->next)
127 		total += sizeof(struct sockaddr_atmsvc);
128 	tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
129 	if (!tmp_buf) {
130 		spin_unlock_irqrestore(&dev->lock, flags);
131 		return -ENOMEM;
132 	}
133 	for (walk = dev->local; walk; walk = walk->next)
134 		memcpy(tmp_bufp++, &walk->addr, sizeof(struct sockaddr_atmsvc));
135 	spin_unlock_irqrestore(&dev->lock, flags);
136 	error = total > size ? -E2BIG : total;
137 	if (copy_to_user(u_buf, tmp_buf, total < size ? total : size))
138 		error = -EFAULT;
139 	kfree(tmp_buf);
140 	return error;
141 }
142