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