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