]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* net/atm/signaling.c - ATM signaling */ |
2 | ||
3 | /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ | |
4 | ||
99824461 | 5 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ |
1da177e4 LT |
6 | |
7 | #include <linux/errno.h> /* error codes */ | |
8 | #include <linux/kernel.h> /* printk */ | |
9 | #include <linux/skbuff.h> | |
10 | #include <linux/wait.h> | |
11 | #include <linux/sched.h> /* jiffies and HZ */ | |
12 | #include <linux/atm.h> /* ATM stuff */ | |
13 | #include <linux/atmsap.h> | |
14 | #include <linux/atmsvc.h> | |
15 | #include <linux/atmdev.h> | |
16 | #include <linux/bitops.h> | |
5a0e3ad6 | 17 | #include <linux/slab.h> |
1da177e4 LT |
18 | |
19 | #include "resources.h" | |
20 | #include "signaling.h" | |
21 | ||
1da177e4 | 22 | struct atm_vcc *sigd = NULL; |
1da177e4 | 23 | |
1da177e4 LT |
24 | static void sigd_put_skb(struct sk_buff *skb) |
25 | { | |
1da177e4 | 26 | if (!sigd) { |
99824461 | 27 | pr_debug("atmsvc: no signaling daemon\n"); |
1da177e4 LT |
28 | kfree_skb(skb); |
29 | return; | |
30 | } | |
0ec96e65 JP |
31 | atm_force_charge(sigd, skb->truesize); |
32 | skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb); | |
676d2369 | 33 | sk_atm(sigd)->sk_data_ready(sk_atm(sigd)); |
1da177e4 LT |
34 | } |
35 | ||
0ec96e65 | 36 | static void modify_qos(struct atm_vcc *vcc, struct atmsvc_msg *msg) |
1da177e4 LT |
37 | { |
38 | struct sk_buff *skb; | |
39 | ||
0ec96e65 JP |
40 | if (test_bit(ATM_VF_RELEASED, &vcc->flags) || |
41 | !test_bit(ATM_VF_READY, &vcc->flags)) | |
1da177e4 LT |
42 | return; |
43 | msg->type = as_error; | |
0ec96e65 JP |
44 | if (!vcc->dev->ops->change_qos) |
45 | msg->reply = -EOPNOTSUPP; | |
1da177e4 LT |
46 | else { |
47 | /* should lock VCC */ | |
0ec96e65 JP |
48 | msg->reply = vcc->dev->ops->change_qos(vcc, &msg->qos, |
49 | msg->reply); | |
50 | if (!msg->reply) | |
51 | msg->type = as_okay; | |
1da177e4 LT |
52 | } |
53 | /* | |
54 | * Should probably just turn around the old skb. But the, the buffer | |
55 | * space accounting needs to follow the change too. Maybe later. | |
56 | */ | |
0ec96e65 | 57 | while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) |
1da177e4 | 58 | schedule(); |
0ec96e65 | 59 | *(struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)) = *msg; |
1da177e4 LT |
60 | sigd_put_skb(skb); |
61 | } | |
62 | ||
0ec96e65 | 63 | static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) |
1da177e4 LT |
64 | { |
65 | struct atmsvc_msg *msg; | |
66 | struct atm_vcc *session_vcc; | |
67 | struct sock *sk; | |
68 | ||
69 | msg = (struct atmsvc_msg *) skb->data; | |
70 | atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); | |
1da177e4 | 71 | vcc = *(struct atm_vcc **) &msg->vcc; |
99824461 | 72 | pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); |
1da177e4 LT |
73 | sk = sk_atm(vcc); |
74 | ||
75 | switch (msg->type) { | |
0ec96e65 JP |
76 | case as_okay: |
77 | sk->sk_err = -msg->reply; | |
78 | clear_bit(ATM_VF_WAITING, &vcc->flags); | |
79 | if (!*vcc->local.sas_addr.prv && !*vcc->local.sas_addr.pub) { | |
80 | vcc->local.sas_family = AF_ATMSVC; | |
81 | memcpy(vcc->local.sas_addr.prv, | |
82 | msg->local.sas_addr.prv, ATM_ESA_LEN); | |
83 | memcpy(vcc->local.sas_addr.pub, | |
84 | msg->local.sas_addr.pub, ATM_E164_LEN + 1); | |
85 | } | |
86 | session_vcc = vcc->session ? vcc->session : vcc; | |
87 | if (session_vcc->vpi || session_vcc->vci) | |
1da177e4 | 88 | break; |
0ec96e65 JP |
89 | session_vcc->itf = msg->pvc.sap_addr.itf; |
90 | session_vcc->vpi = msg->pvc.sap_addr.vpi; | |
91 | session_vcc->vci = msg->pvc.sap_addr.vci; | |
92 | if (session_vcc->vpi || session_vcc->vci) | |
93 | session_vcc->qos = msg->qos; | |
94 | break; | |
95 | case as_error: | |
96 | clear_bit(ATM_VF_REGIS, &vcc->flags); | |
97 | clear_bit(ATM_VF_READY, &vcc->flags); | |
98 | sk->sk_err = -msg->reply; | |
99 | clear_bit(ATM_VF_WAITING, &vcc->flags); | |
100 | break; | |
101 | case as_indicate: | |
102 | vcc = *(struct atm_vcc **)&msg->listen_vcc; | |
103 | sk = sk_atm(vcc); | |
104 | pr_debug("as_indicate!!!\n"); | |
105 | lock_sock(sk); | |
106 | if (sk_acceptq_is_full(sk)) { | |
107 | sigd_enq(NULL, as_reject, vcc, NULL, NULL); | |
108 | dev_kfree_skb(skb); | |
109 | goto as_indicate_complete; | |
110 | } | |
111 | sk->sk_ack_backlog++; | |
112 | skb_queue_tail(&sk->sk_receive_queue, skb); | |
aa395145 | 113 | pr_debug("waking sk_sleep(sk) 0x%p\n", sk_sleep(sk)); |
0ec96e65 | 114 | sk->sk_state_change(sk); |
1da177e4 | 115 | as_indicate_complete: |
0ec96e65 JP |
116 | release_sock(sk); |
117 | return 0; | |
118 | case as_close: | |
119 | set_bit(ATM_VF_RELEASED, &vcc->flags); | |
120 | vcc_release_async(vcc, msg->reply); | |
121 | goto out; | |
122 | case as_modify: | |
123 | modify_qos(vcc, msg); | |
124 | break; | |
125 | case as_addparty: | |
126 | case as_dropparty: | |
127 | sk->sk_err_soft = msg->reply; | |
128 | /* < 0 failure, otherwise ep_ref */ | |
129 | clear_bit(ATM_VF_WAITING, &vcc->flags); | |
130 | break; | |
131 | default: | |
132 | pr_alert("bad message type %d\n", (int)msg->type); | |
133 | return -EINVAL; | |
1da177e4 LT |
134 | } |
135 | sk->sk_state_change(sk); | |
136 | out: | |
137 | dev_kfree_skb(skb); | |
138 | return 0; | |
139 | } | |
140 | ||
0ec96e65 JP |
141 | void sigd_enq2(struct atm_vcc *vcc, enum atmsvc_msg_type type, |
142 | struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc, | |
143 | const struct sockaddr_atmsvc *svc, const struct atm_qos *qos, | |
144 | int reply) | |
1da177e4 LT |
145 | { |
146 | struct sk_buff *skb; | |
147 | struct atmsvc_msg *msg; | |
95c96174 | 148 | static unsigned int session = 0; |
1da177e4 | 149 | |
99824461 | 150 | pr_debug("%d (0x%p)\n", (int)type, vcc); |
0ec96e65 | 151 | while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) |
1da177e4 | 152 | schedule(); |
0ec96e65 JP |
153 | msg = (struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)); |
154 | memset(msg, 0, sizeof(*msg)); | |
1da177e4 LT |
155 | msg->type = type; |
156 | *(struct atm_vcc **) &msg->vcc = vcc; | |
157 | *(struct atm_vcc **) &msg->listen_vcc = listen_vcc; | |
158 | msg->reply = reply; | |
0ec96e65 JP |
159 | if (qos) |
160 | msg->qos = *qos; | |
161 | if (vcc) | |
162 | msg->sap = vcc->sap; | |
163 | if (svc) | |
164 | msg->svc = *svc; | |
165 | if (vcc) | |
166 | msg->local = vcc->local; | |
167 | if (pvc) | |
168 | msg->pvc = *pvc; | |
1da177e4 LT |
169 | if (vcc) { |
170 | if (type == as_connect && test_bit(ATM_VF_SESSION, &vcc->flags)) | |
171 | msg->session = ++session; | |
172 | /* every new pmp connect gets the next session number */ | |
173 | } | |
174 | sigd_put_skb(skb); | |
0ec96e65 JP |
175 | if (vcc) |
176 | set_bit(ATM_VF_REGIS, &vcc->flags); | |
1da177e4 LT |
177 | } |
178 | ||
0ec96e65 JP |
179 | void sigd_enq(struct atm_vcc *vcc, enum atmsvc_msg_type type, |
180 | struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc, | |
181 | const struct sockaddr_atmsvc *svc) | |
1da177e4 | 182 | { |
0ec96e65 | 183 | sigd_enq2(vcc, type, listen_vcc, pvc, svc, vcc ? &vcc->qos : NULL, 0); |
1da177e4 LT |
184 | /* other ISP applications may use "reply" */ |
185 | } | |
186 | ||
1da177e4 LT |
187 | static void purge_vcc(struct atm_vcc *vcc) |
188 | { | |
189 | if (sk_atm(vcc)->sk_family == PF_ATMSVC && | |
9301e320 CW |
190 | !test_bit(ATM_VF_META, &vcc->flags)) { |
191 | set_bit(ATM_VF_RELEASED, &vcc->flags); | |
192 | clear_bit(ATM_VF_REGIS, &vcc->flags); | |
1da177e4 LT |
193 | vcc_release_async(vcc, -EUNATCH); |
194 | } | |
195 | } | |
196 | ||
1da177e4 LT |
197 | static void sigd_close(struct atm_vcc *vcc) |
198 | { | |
1da177e4 LT |
199 | struct sock *s; |
200 | int i; | |
201 | ||
99824461 | 202 | pr_debug("\n"); |
1da177e4 LT |
203 | sigd = NULL; |
204 | if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) | |
99824461 | 205 | pr_err("closing with requests pending\n"); |
1da177e4 LT |
206 | skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); |
207 | ||
208 | read_lock(&vcc_sklist_lock); | |
0ec96e65 | 209 | for (i = 0; i < VCC_HTABLE_SIZE; ++i) { |
1da177e4 LT |
210 | struct hlist_head *head = &vcc_hash[i]; |
211 | ||
b67bfe0d | 212 | sk_for_each(s, head) { |
cfcabdcc | 213 | vcc = atm_sk(s); |
1da177e4 | 214 | |
9301e320 | 215 | purge_vcc(vcc); |
1da177e4 LT |
216 | } |
217 | } | |
218 | read_unlock(&vcc_sklist_lock); | |
219 | } | |
220 | ||
1da177e4 LT |
221 | static struct atmdev_ops sigd_dev_ops = { |
222 | .close = sigd_close, | |
223 | .send = sigd_send | |
224 | }; | |
225 | ||
1da177e4 LT |
226 | static struct atm_dev sigd_dev = { |
227 | .ops = &sigd_dev_ops, | |
228 | .type = "sig", | |
229 | .number = 999, | |
4ef8d0ae | 230 | .lock = __SPIN_LOCK_UNLOCKED(sigd_dev.lock) |
1da177e4 LT |
231 | }; |
232 | ||
1da177e4 LT |
233 | int sigd_attach(struct atm_vcc *vcc) |
234 | { | |
0ec96e65 JP |
235 | if (sigd) |
236 | return -EADDRINUSE; | |
99824461 | 237 | pr_debug("\n"); |
1da177e4 LT |
238 | sigd = vcc; |
239 | vcc->dev = &sigd_dev; | |
240 | vcc_insert_socket(sk_atm(vcc)); | |
0ec96e65 JP |
241 | set_bit(ATM_VF_META, &vcc->flags); |
242 | set_bit(ATM_VF_READY, &vcc->flags); | |
1da177e4 LT |
243 | return 0; |
244 | } |