Lines Matching +full:wakeup +full:- +full:capable
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* net/atm/pppoatm.c - RFC2364 PPP over ATM/AAL5 */
4 /* Copyright 1999-2000 by Mitchell Blank Jr */
5 /* Based on clip.c; 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
17 * section 8 of RFC2364 - we are supposed to detect a change
19 * to avoid a black-hole being created if our peer loses state
24 * 1. LLC-encapsulation was missing when it was enabled. In
27 * 2. LLC-encapsulation was present when it was disabled. Then
44 #include <linux/ppp-ioctl.h>
66 int flags; /* SC_COMP_PROT - compress protocol */
75 * inflight == -2 represents an empty queue, -1 one packet, and zero means
78 #define NONE_INFLIGHT -2
91 return (struct pppoatm_vcc *) (atmvcc->user_back); in atmvcc_to_pvcc()
96 return (struct pppoatm_vcc *) (chan->private); in chan_to_pvcc()
108 ppp_output_wakeup(&pvcc->chan); in pppoatm_wakeup_sender()
117 * the wakeup *can't* race with pppoatm_send(). They both hold the PPP in pppoatm_release_cb()
118 * channel's ->downl lock. And the potential race with *setting* it, in pppoatm_release_cb()
119 * which leads to the double-check dance in pppoatm_may_send(), doesn't in pppoatm_release_cb()
122 * ->release_cb() can't be called until that's done. in pppoatm_release_cb()
124 if (test_and_clear_bit(BLOCKED, &pvcc->blocked)) in pppoatm_release_cb()
125 tasklet_schedule(&pvcc->wakeup_tasklet); in pppoatm_release_cb()
126 if (pvcc->old_release_cb) in pppoatm_release_cb()
127 pvcc->old_release_cb(atmvcc); in pppoatm_release_cb()
131 * skb. The ->old_pop will take care up normal atm flow control,
138 pvcc->old_pop(atmvcc, skb); in pppoatm_pop()
139 atomic_dec(&pvcc->inflight); in pppoatm_pop()
142 * We always used to run the wakeup tasklet unconditionally here, for in pppoatm_pop()
147 * while holding the channel->downl lock. And ppp_output_wakeup() as in pppoatm_pop()
150 * with it. The wakeup *will* happen after the other CPU is safely out in pppoatm_pop()
154 * it about to return, that's fine. We trigger a wakeup which will in pppoatm_pop()
159 if (test_and_clear_bit(BLOCKED, &pvcc->blocked)) in pppoatm_pop()
160 tasklet_schedule(&pvcc->wakeup_tasklet); in pppoatm_pop()
164 * Unbind from PPP - currently we only do this when closing the socket,
171 atmvcc->push = pvcc->old_push; in pppoatm_unassign_vcc()
172 atmvcc->pop = pvcc->old_pop; in pppoatm_unassign_vcc()
173 atmvcc->release_cb = pvcc->old_release_cb; in pppoatm_unassign_vcc()
174 tasklet_kill(&pvcc->wakeup_tasklet); in pppoatm_unassign_vcc()
175 ppp_unregister_channel(&pvcc->chan); in pppoatm_unassign_vcc()
176 atmvcc->user_back = NULL; in pppoatm_unassign_vcc()
189 module = pvcc->old_owner; in pppoatm_push()
191 atmvcc->push(atmvcc, NULL); /* Pass along bad news */ in pppoatm_push()
195 atm_return(atmvcc, skb->truesize); in pppoatm_push()
196 switch (pvcc->encaps) { in pppoatm_push()
198 if (skb->len < LLC_LEN || in pppoatm_push()
199 memcmp(skb->data, pppllc, LLC_LEN)) in pppoatm_push()
204 if (pvcc->chan.ppp == NULL) { /* Not bound yet! */ in pppoatm_push()
208 if (skb->len >= sizeof(pppllc) && in pppoatm_push()
209 !memcmp(skb->data, pppllc, sizeof(pppllc))) { in pppoatm_push()
210 pvcc->encaps = e_llc; in pppoatm_push()
214 if (skb->len >= (sizeof(pppllc) - LLC_LEN) && in pppoatm_push()
215 !memcmp(skb->data, &pppllc[LLC_LEN], in pppoatm_push()
216 sizeof(pppllc) - LLC_LEN)) { in pppoatm_push()
217 pvcc->encaps = e_vc; in pppoatm_push()
218 pvcc->chan.mtu += LLC_LEN; in pppoatm_push()
221 pr_debug("Couldn't autodetect yet (skb: %6ph)\n", skb->data); in pppoatm_push()
226 ppp_input(&pvcc->chan, skb); in pppoatm_push()
231 ppp_input_error(&pvcc->chan, 0); in pppoatm_push()
238 * to check we don't exceed sk->sk_sndbuf. If userspace sets a in pppoatm_may_send()
243 if (atm_may_send(pvcc->atmvcc, size) && in pppoatm_may_send()
244 atomic_inc_not_zero(&pvcc->inflight)) in pppoatm_may_send()
250 * *must* be set before we do the atomic_inc() on pvcc->inflight. in pppoatm_may_send()
254 test_and_set_bit(BLOCKED, &pvcc->blocked); in pppoatm_may_send()
264 * run the wakeup tasklet. Another wakeup will never hurt. in pppoatm_may_send()
268 * an "immediate" wakeup... where "immediate" actually involves in pppoatm_may_send()
269 * taking the PPP channel's ->downl lock, which is held by the in pppoatm_may_send()
273 if (atm_may_send(pvcc->atmvcc, size) && in pppoatm_may_send()
274 atomic_inc_not_zero(&pvcc->inflight)) in pppoatm_may_send()
280 * Called by the ppp_generic.c to send a packet - returns true if packet
295 ATM_SKB(skb)->vcc = pvcc->atmvcc; in pppoatm_send()
296 pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); in pppoatm_send()
297 if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) in pppoatm_send()
300 vcc = ATM_SKB(skb)->vcc; in pppoatm_send()
305 * the socket. It needs to be seen by the time our ->release_cb gets in pppoatm_send()
308 test_and_set_bit(BLOCKED, &pvcc->blocked); in pppoatm_send()
311 if (test_bit(ATM_VF_RELEASED, &vcc->flags) || in pppoatm_send()
312 test_bit(ATM_VF_CLOSE, &vcc->flags) || in pppoatm_send()
313 !test_bit(ATM_VF_READY, &vcc->flags)) { in pppoatm_send()
319 switch (pvcc->encaps) { /* LLC encapsulation needed */ in pppoatm_send()
325 !pppoatm_may_send(pvcc, n->truesize)) { in pppoatm_send()
335 } else if (!pppoatm_may_send(pvcc, skb->truesize)) in pppoatm_send()
340 if (!pppoatm_may_send(pvcc, skb->truesize)) in pppoatm_send()
351 pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", in pppoatm_send()
352 skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); in pppoatm_send()
353 ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) in pppoatm_send()
363 if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 && in pppoatm_send()
364 skb->data[-1] == '\0') in pppoatm_send()
375 return put_user(chan_to_pvcc(chan)->flags, (int __user *) arg) in pppoatm_devppp_ioctl()
376 ? -EFAULT : 0; in pppoatm_devppp_ioctl()
378 return get_user(chan_to_pvcc(chan)->flags, (int __user *) arg) in pppoatm_devppp_ioctl()
379 ? -EFAULT : 0; in pppoatm_devppp_ioctl()
381 return -ENOTTY; in pppoatm_devppp_ioctl()
396 return -EFAULT; in pppoatm_assign_vcc()
399 return -EINVAL; in pppoatm_assign_vcc()
402 return -ENOMEM; in pppoatm_assign_vcc()
403 pvcc->atmvcc = atmvcc; in pppoatm_assign_vcc()
406 atomic_set(&pvcc->inflight, NONE_INFLIGHT); in pppoatm_assign_vcc()
407 pvcc->old_push = atmvcc->push; in pppoatm_assign_vcc()
408 pvcc->old_pop = atmvcc->pop; in pppoatm_assign_vcc()
409 pvcc->old_owner = atmvcc->owner; in pppoatm_assign_vcc()
410 pvcc->old_release_cb = atmvcc->release_cb; in pppoatm_assign_vcc()
411 pvcc->encaps = (enum pppoatm_encaps) be.encaps; in pppoatm_assign_vcc()
412 pvcc->chan.private = pvcc; in pppoatm_assign_vcc()
413 pvcc->chan.ops = &pppoatm_ops; in pppoatm_assign_vcc()
414 pvcc->chan.mtu = atmvcc->qos.txtp.max_sdu - PPP_HDRLEN - in pppoatm_assign_vcc()
416 tasklet_setup(&pvcc->wakeup_tasklet, pppoatm_wakeup_sender); in pppoatm_assign_vcc()
417 err = ppp_register_channel(&pvcc->chan); in pppoatm_assign_vcc()
422 atmvcc->user_back = pvcc; in pppoatm_assign_vcc()
423 atmvcc->push = pppoatm_push; in pppoatm_assign_vcc()
424 atmvcc->pop = pppoatm_pop; in pppoatm_assign_vcc()
425 atmvcc->release_cb = pppoatm_release_cb; in pppoatm_assign_vcc()
427 atmvcc->owner = THIS_MODULE; in pppoatm_assign_vcc()
429 /* re-process everything received between connection setup and in pppoatm_assign_vcc()
436 * This handles ioctls actually performed on our vcc - we must return
437 * -ENOIOCTLCMD for any unrecognized ioctl
445 if (cmd != ATM_SETBACKEND && atmvcc->push != pppoatm_push) in pppoatm_ioctl()
446 return -ENOIOCTLCMD; in pppoatm_ioctl()
451 return -EFAULT; in pppoatm_ioctl()
453 return -ENOIOCTLCMD; in pppoatm_ioctl()
454 if (!capable(CAP_NET_ADMIN)) in pppoatm_ioctl()
455 return -EPERM; in pppoatm_ioctl()
456 if (sock->state != SS_CONNECTED) in pppoatm_ioctl()
457 return -EINVAL; in pppoatm_ioctl()
461 return put_user(ppp_channel_index(&atmvcc_to_pvcc(atmvcc)-> in pppoatm_ioctl()
462 chan), (int __user *) argp) ? -EFAULT : 0; in pppoatm_ioctl()
464 return put_user(ppp_unit_number(&atmvcc_to_pvcc(atmvcc)-> in pppoatm_ioctl()
465 chan), (int __user *) argp) ? -EFAULT : 0; in pppoatm_ioctl()
467 return -ENOIOCTLCMD; in pppoatm_ioctl()