Blame view
net/atm/signaling.c
6.83 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 |
/* net/atm/signaling.c - ATM signaling */ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ |
99824461e net/atm: Convert ... |
4 |
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ |
1da177e4c Linux-2.6.12-rc2 |
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 include cleanup: ... |
16 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 |
#include "resources.h" #include "signaling.h" |
1da177e4c Linux-2.6.12-rc2 |
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 Linux-2.6.12-rc2 |
24 25 26 27 |
struct atm_vcc *sigd = NULL; #ifdef WAIT_FOR_DEMON static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep); #endif |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 |
static void sigd_put_skb(struct sk_buff *skb) { #ifdef WAIT_FOR_DEMON |
0ec96e656 net/atm/signaling... |
31 |
DECLARE_WAITQUEUE(wait, current); |
1da177e4c Linux-2.6.12-rc2 |
32 |
|
0ec96e656 net/atm/signaling... |
33 |
add_wait_queue(&sigd_sleep, &wait); |
1da177e4c Linux-2.6.12-rc2 |
34 35 |
while (!sigd) { set_current_state(TASK_UNINTERRUPTIBLE); |
99824461e net/atm: Convert ... |
36 37 |
pr_debug("atmsvc: waiting for signaling daemon... "); |
1da177e4c Linux-2.6.12-rc2 |
38 39 40 |
schedule(); } current->state = TASK_RUNNING; |
0ec96e656 net/atm/signaling... |
41 |
remove_wait_queue(&sigd_sleep, &wait); |
1da177e4c Linux-2.6.12-rc2 |
42 43 |
#else if (!sigd) { |
99824461e net/atm: Convert ... |
44 45 |
pr_debug("atmsvc: no signaling daemon "); |
1da177e4c Linux-2.6.12-rc2 |
46 47 48 49 |
kfree_skb(skb); return; } #endif |
0ec96e656 net/atm/signaling... |
50 51 |
atm_force_charge(sigd, skb->truesize); skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb); |
1da177e4c Linux-2.6.12-rc2 |
52 53 |
sk_atm(sigd)->sk_data_ready(sk_atm(sigd), skb->len); } |
0ec96e656 net/atm/signaling... |
54 |
static void modify_qos(struct atm_vcc *vcc, struct atmsvc_msg *msg) |
1da177e4c Linux-2.6.12-rc2 |
55 56 |
{ struct sk_buff *skb; |
0ec96e656 net/atm/signaling... |
57 58 |
if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !test_bit(ATM_VF_READY, &vcc->flags)) |
1da177e4c Linux-2.6.12-rc2 |
59 60 |
return; msg->type = as_error; |
0ec96e656 net/atm/signaling... |
61 62 |
if (!vcc->dev->ops->change_qos) msg->reply = -EOPNOTSUPP; |
1da177e4c Linux-2.6.12-rc2 |
63 64 |
else { /* should lock VCC */ |
0ec96e656 net/atm/signaling... |
65 66 67 68 |
msg->reply = vcc->dev->ops->change_qos(vcc, &msg->qos, msg->reply); if (!msg->reply) msg->type = as_okay; |
1da177e4c Linux-2.6.12-rc2 |
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 net/atm/signaling... |
74 |
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) |
1da177e4c Linux-2.6.12-rc2 |
75 |
schedule(); |
0ec96e656 net/atm/signaling... |
76 |
*(struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)) = *msg; |
1da177e4c Linux-2.6.12-rc2 |
77 78 |
sigd_put_skb(skb); } |
0ec96e656 net/atm/signaling... |
79 |
static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) |
1da177e4c Linux-2.6.12-rc2 |
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 Linux-2.6.12-rc2 |
87 |
vcc = *(struct atm_vcc **) &msg->vcc; |
99824461e net/atm: Convert ... |
88 89 |
pr_debug("%d (0x%lx) ", (int)msg->type, (unsigned long)vcc); |
1da177e4c Linux-2.6.12-rc2 |
90 91 92 |
sk = sk_atm(vcc); switch (msg->type) { |
0ec96e656 net/atm/signaling... |
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 Linux-2.6.12-rc2 |
105 |
break; |
0ec96e656 net/atm/signaling... |
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 net: sk_sleep() h... |
131 132 |
pr_debug("waking sk_sleep(sk) 0x%p ", sk_sleep(sk)); |
0ec96e656 net/atm/signaling... |
133 |
sk->sk_state_change(sk); |
1da177e4c Linux-2.6.12-rc2 |
134 |
as_indicate_complete: |
0ec96e656 net/atm/signaling... |
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 Linux-2.6.12-rc2 |
154 155 156 157 158 159 |
} sk->sk_state_change(sk); out: dev_kfree_skb(skb); return 0; } |
0ec96e656 net/atm/signaling... |
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 Linux-2.6.12-rc2 |
164 165 166 |
{ struct sk_buff *skb; struct atmsvc_msg *msg; |
95c961747 net: cleanup unsi... |
167 |
static unsigned int session = 0; |
1da177e4c Linux-2.6.12-rc2 |
168 |
|
99824461e net/atm: Convert ... |
169 170 |
pr_debug("%d (0x%p) ", (int)type, vcc); |
0ec96e656 net/atm/signaling... |
171 |
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) |
1da177e4c Linux-2.6.12-rc2 |
172 |
schedule(); |
0ec96e656 net/atm/signaling... |
173 174 |
msg = (struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)); memset(msg, 0, sizeof(*msg)); |
1da177e4c Linux-2.6.12-rc2 |
175 176 177 178 |
msg->type = type; *(struct atm_vcc **) &msg->vcc = vcc; *(struct atm_vcc **) &msg->listen_vcc = listen_vcc; msg->reply = reply; |
0ec96e656 net/atm/signaling... |
179 180 181 182 183 184 185 186 187 188 |
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 Linux-2.6.12-rc2 |
189 190 191 192 193 194 |
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 net/atm/signaling... |
195 196 |
if (vcc) set_bit(ATM_VF_REGIS, &vcc->flags); |
1da177e4c Linux-2.6.12-rc2 |
197 |
} |
0ec96e656 net/atm/signaling... |
198 199 200 |
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 Linux-2.6.12-rc2 |
201 |
{ |
0ec96e656 net/atm/signaling... |
202 |
sigd_enq2(vcc, type, listen_vcc, pvc, svc, vcc ? &vcc->qos : NULL, 0); |
1da177e4c Linux-2.6.12-rc2 |
203 204 |
/* other ISP applications may use "reply" */ } |
1da177e4c Linux-2.6.12-rc2 |
205 206 207 |
static void purge_vcc(struct atm_vcc *vcc) { if (sk_atm(vcc)->sk_family == PF_ATMSVC && |
9301e320e [ATM]: track and ... |
208 209 210 |
!test_bit(ATM_VF_META, &vcc->flags)) { set_bit(ATM_VF_RELEASED, &vcc->flags); clear_bit(ATM_VF_REGIS, &vcc->flags); |
1da177e4c Linux-2.6.12-rc2 |
211 212 213 |
vcc_release_async(vcc, -EUNATCH); } } |
1da177e4c Linux-2.6.12-rc2 |
214 215 |
static void sigd_close(struct atm_vcc *vcc) { |
1da177e4c Linux-2.6.12-rc2 |
216 217 |
struct sock *s; int i; |
99824461e net/atm: Convert ... |
218 219 |
pr_debug(" "); |
1da177e4c Linux-2.6.12-rc2 |
220 221 |
sigd = NULL; if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) |
99824461e net/atm: Convert ... |
222 223 |
pr_err("closing with requests pending "); |
1da177e4c Linux-2.6.12-rc2 |
224 225 226 |
skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); read_lock(&vcc_sklist_lock); |
0ec96e656 net/atm/signaling... |
227 |
for (i = 0; i < VCC_HTABLE_SIZE; ++i) { |
1da177e4c Linux-2.6.12-rc2 |
228 |
struct hlist_head *head = &vcc_hash[i]; |
b67bfe0d4 hlist: drop the n... |
229 |
sk_for_each(s, head) { |
cfcabdcc2 [NET]: sparse war... |
230 |
vcc = atm_sk(s); |
1da177e4c Linux-2.6.12-rc2 |
231 |
|
9301e320e [ATM]: track and ... |
232 |
purge_vcc(vcc); |
1da177e4c Linux-2.6.12-rc2 |
233 234 235 236 |
} } read_unlock(&vcc_sklist_lock); } |
1da177e4c Linux-2.6.12-rc2 |
237 238 239 240 |
static struct atmdev_ops sigd_dev_ops = { .close = sigd_close, .send = sigd_send }; |
1da177e4c Linux-2.6.12-rc2 |
241 242 243 244 |
static struct atm_dev sigd_dev = { .ops = &sigd_dev_ops, .type = "sig", .number = 999, |
4ef8d0aea [NET]: SPIN_LOCK_... |
245 |
.lock = __SPIN_LOCK_UNLOCKED(sigd_dev.lock) |
1da177e4c Linux-2.6.12-rc2 |
246 |
}; |
1da177e4c Linux-2.6.12-rc2 |
247 248 |
int sigd_attach(struct atm_vcc *vcc) { |
0ec96e656 net/atm/signaling... |
249 250 |
if (sigd) return -EADDRINUSE; |
99824461e net/atm: Convert ... |
251 252 |
pr_debug(" "); |
1da177e4c Linux-2.6.12-rc2 |
253 254 255 |
sigd = vcc; vcc->dev = &sigd_dev; vcc_insert_socket(sk_atm(vcc)); |
0ec96e656 net/atm/signaling... |
256 257 |
set_bit(ATM_VF_META, &vcc->flags); set_bit(ATM_VF_READY, &vcc->flags); |
1da177e4c Linux-2.6.12-rc2 |
258 259 260 261 262 |
#ifdef WAIT_FOR_DEMON wake_up(&sigd_sleep); #endif return 0; } |