0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
0034
0035 #include <linux/module.h>
0036 #include <linux/init.h>
0037 #include <linux/interrupt.h>
0038 #include <linux/skbuff.h>
0039 #include <linux/slab.h>
0040 #include <linux/atm.h>
0041 #include <linux/atmdev.h>
0042 #include <linux/capability.h>
0043 #include <linux/ppp_defs.h>
0044 #include <linux/ppp-ioctl.h>
0045 #include <linux/ppp_channel.h>
0046 #include <linux/atmppp.h>
0047
0048 #include "common.h"
0049
0050 enum pppoatm_encaps {
0051 e_autodetect = PPPOATM_ENCAPS_AUTODETECT,
0052 e_vc = PPPOATM_ENCAPS_VC,
0053 e_llc = PPPOATM_ENCAPS_LLC,
0054 };
0055
0056 struct pppoatm_vcc {
0057 struct atm_vcc *atmvcc;
0058 void (*old_push)(struct atm_vcc *, struct sk_buff *);
0059 void (*old_pop)(struct atm_vcc *, struct sk_buff *);
0060 void (*old_release_cb)(struct atm_vcc *);
0061 struct module *old_owner;
0062
0063 enum pppoatm_encaps encaps;
0064 atomic_t inflight;
0065 unsigned long blocked;
0066 int flags;
0067 struct ppp_channel chan;
0068 struct tasklet_struct wakeup_tasklet;
0069 };
0070
0071
0072
0073
0074
0075
0076
0077
0078 #define NONE_INFLIGHT -2
0079
0080 #define BLOCKED 0
0081
0082
0083
0084
0085
0086 static const unsigned char pppllc[6] = { 0xFE, 0xFE, 0x03, 0xCF, 0xC0, 0x21 };
0087 #define LLC_LEN (4)
0088
0089 static inline struct pppoatm_vcc *atmvcc_to_pvcc(const struct atm_vcc *atmvcc)
0090 {
0091 return (struct pppoatm_vcc *) (atmvcc->user_back);
0092 }
0093
0094 static inline struct pppoatm_vcc *chan_to_pvcc(const struct ppp_channel *chan)
0095 {
0096 return (struct pppoatm_vcc *) (chan->private);
0097 }
0098
0099
0100
0101
0102
0103
0104 static void pppoatm_wakeup_sender(struct tasklet_struct *t)
0105 {
0106 struct pppoatm_vcc *pvcc = from_tasklet(pvcc, t, wakeup_tasklet);
0107
0108 ppp_output_wakeup(&pvcc->chan);
0109 }
0110
0111 static void pppoatm_release_cb(struct atm_vcc *atmvcc)
0112 {
0113 struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124 if (test_and_clear_bit(BLOCKED, &pvcc->blocked))
0125 tasklet_schedule(&pvcc->wakeup_tasklet);
0126 if (pvcc->old_release_cb)
0127 pvcc->old_release_cb(atmvcc);
0128 }
0129
0130
0131
0132
0133
0134 static void pppoatm_pop(struct atm_vcc *atmvcc, struct sk_buff *skb)
0135 {
0136 struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
0137
0138 pvcc->old_pop(atmvcc, skb);
0139 atomic_dec(&pvcc->inflight);
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 if (test_and_clear_bit(BLOCKED, &pvcc->blocked))
0160 tasklet_schedule(&pvcc->wakeup_tasklet);
0161 }
0162
0163
0164
0165
0166
0167 static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc)
0168 {
0169 struct pppoatm_vcc *pvcc;
0170 pvcc = atmvcc_to_pvcc(atmvcc);
0171 atmvcc->push = pvcc->old_push;
0172 atmvcc->pop = pvcc->old_pop;
0173 atmvcc->release_cb = pvcc->old_release_cb;
0174 tasklet_kill(&pvcc->wakeup_tasklet);
0175 ppp_unregister_channel(&pvcc->chan);
0176 atmvcc->user_back = NULL;
0177 kfree(pvcc);
0178 }
0179
0180
0181 static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
0182 {
0183 struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
0184 pr_debug("\n");
0185 if (skb == NULL) {
0186 struct module *module;
0187
0188 pr_debug("removing ATMPPP VCC %p\n", pvcc);
0189 module = pvcc->old_owner;
0190 pppoatm_unassign_vcc(atmvcc);
0191 atmvcc->push(atmvcc, NULL);
0192 module_put(module);
0193 return;
0194 }
0195 atm_return(atmvcc, skb->truesize);
0196 switch (pvcc->encaps) {
0197 case e_llc:
0198 if (skb->len < LLC_LEN ||
0199 memcmp(skb->data, pppllc, LLC_LEN))
0200 goto error;
0201 skb_pull(skb, LLC_LEN);
0202 break;
0203 case e_autodetect:
0204 if (pvcc->chan.ppp == NULL) {
0205 kfree_skb(skb);
0206 return;
0207 }
0208 if (skb->len >= sizeof(pppllc) &&
0209 !memcmp(skb->data, pppllc, sizeof(pppllc))) {
0210 pvcc->encaps = e_llc;
0211 skb_pull(skb, LLC_LEN);
0212 break;
0213 }
0214 if (skb->len >= (sizeof(pppllc) - LLC_LEN) &&
0215 !memcmp(skb->data, &pppllc[LLC_LEN],
0216 sizeof(pppllc) - LLC_LEN)) {
0217 pvcc->encaps = e_vc;
0218 pvcc->chan.mtu += LLC_LEN;
0219 break;
0220 }
0221 pr_debug("Couldn't autodetect yet (skb: %6ph)\n", skb->data);
0222 goto error;
0223 case e_vc:
0224 break;
0225 }
0226 ppp_input(&pvcc->chan, skb);
0227 return;
0228
0229 error:
0230 kfree_skb(skb);
0231 ppp_input_error(&pvcc->chan, 0);
0232 }
0233
0234 static int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size)
0235 {
0236
0237
0238
0239
0240
0241
0242
0243 if (atm_may_send(pvcc->atmvcc, size) &&
0244 atomic_inc_not_zero(&pvcc->inflight))
0245 return 1;
0246
0247
0248
0249
0250
0251
0252
0253
0254 test_and_set_bit(BLOCKED, &pvcc->blocked);
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273 if (atm_may_send(pvcc->atmvcc, size) &&
0274 atomic_inc_not_zero(&pvcc->inflight))
0275 return 1;
0276
0277 return 0;
0278 }
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288 #define DROP_PACKET 1
0289 static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
0290 {
0291 struct pppoatm_vcc *pvcc = chan_to_pvcc(chan);
0292 struct atm_vcc *vcc;
0293 int ret;
0294
0295 ATM_SKB(skb)->vcc = pvcc->atmvcc;
0296 pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
0297 if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
0298 (void) skb_pull(skb, 1);
0299
0300 vcc = ATM_SKB(skb)->vcc;
0301 bh_lock_sock(sk_atm(vcc));
0302 if (sock_owned_by_user(sk_atm(vcc))) {
0303
0304
0305
0306
0307
0308 test_and_set_bit(BLOCKED, &pvcc->blocked);
0309 goto nospace;
0310 }
0311 if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
0312 test_bit(ATM_VF_CLOSE, &vcc->flags) ||
0313 !test_bit(ATM_VF_READY, &vcc->flags)) {
0314 bh_unlock_sock(sk_atm(vcc));
0315 kfree_skb(skb);
0316 return DROP_PACKET;
0317 }
0318
0319 switch (pvcc->encaps) {
0320 case e_llc:
0321 if (skb_headroom(skb) < LLC_LEN) {
0322 struct sk_buff *n;
0323 n = skb_realloc_headroom(skb, LLC_LEN);
0324 if (n != NULL &&
0325 !pppoatm_may_send(pvcc, n->truesize)) {
0326 kfree_skb(n);
0327 goto nospace;
0328 }
0329 consume_skb(skb);
0330 skb = n;
0331 if (skb == NULL) {
0332 bh_unlock_sock(sk_atm(vcc));
0333 return DROP_PACKET;
0334 }
0335 } else if (!pppoatm_may_send(pvcc, skb->truesize))
0336 goto nospace;
0337 memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
0338 break;
0339 case e_vc:
0340 if (!pppoatm_may_send(pvcc, skb->truesize))
0341 goto nospace;
0342 break;
0343 case e_autodetect:
0344 bh_unlock_sock(sk_atm(vcc));
0345 pr_debug("Trying to send without setting encaps!\n");
0346 kfree_skb(skb);
0347 return 1;
0348 }
0349
0350 atm_account_tx(vcc, skb);
0351 pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
0352 skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
0353 ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)
0354 ? DROP_PACKET : 1;
0355 bh_unlock_sock(sk_atm(vcc));
0356 return ret;
0357 nospace:
0358 bh_unlock_sock(sk_atm(vcc));
0359
0360
0361
0362
0363 if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 &&
0364 skb->data[-1] == '\0')
0365 (void) skb_push(skb, 1);
0366 return 0;
0367 }
0368
0369
0370 static int pppoatm_devppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
0371 unsigned long arg)
0372 {
0373 switch (cmd) {
0374 case PPPIOCGFLAGS:
0375 return put_user(chan_to_pvcc(chan)->flags, (int __user *) arg)
0376 ? -EFAULT : 0;
0377 case PPPIOCSFLAGS:
0378 return get_user(chan_to_pvcc(chan)->flags, (int __user *) arg)
0379 ? -EFAULT : 0;
0380 }
0381 return -ENOTTY;
0382 }
0383
0384 static const struct ppp_channel_ops pppoatm_ops = {
0385 .start_xmit = pppoatm_send,
0386 .ioctl = pppoatm_devppp_ioctl,
0387 };
0388
0389 static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)
0390 {
0391 struct atm_backend_ppp be;
0392 struct pppoatm_vcc *pvcc;
0393 int err;
0394
0395 if (copy_from_user(&be, arg, sizeof be))
0396 return -EFAULT;
0397 if (be.encaps != PPPOATM_ENCAPS_AUTODETECT &&
0398 be.encaps != PPPOATM_ENCAPS_VC && be.encaps != PPPOATM_ENCAPS_LLC)
0399 return -EINVAL;
0400 pvcc = kzalloc(sizeof(*pvcc), GFP_KERNEL);
0401 if (pvcc == NULL)
0402 return -ENOMEM;
0403 pvcc->atmvcc = atmvcc;
0404
0405
0406 atomic_set(&pvcc->inflight, NONE_INFLIGHT);
0407 pvcc->old_push = atmvcc->push;
0408 pvcc->old_pop = atmvcc->pop;
0409 pvcc->old_owner = atmvcc->owner;
0410 pvcc->old_release_cb = atmvcc->release_cb;
0411 pvcc->encaps = (enum pppoatm_encaps) be.encaps;
0412 pvcc->chan.private = pvcc;
0413 pvcc->chan.ops = &pppoatm_ops;
0414 pvcc->chan.mtu = atmvcc->qos.txtp.max_sdu - PPP_HDRLEN -
0415 (be.encaps == e_vc ? 0 : LLC_LEN);
0416 tasklet_setup(&pvcc->wakeup_tasklet, pppoatm_wakeup_sender);
0417 err = ppp_register_channel(&pvcc->chan);
0418 if (err != 0) {
0419 kfree(pvcc);
0420 return err;
0421 }
0422 atmvcc->user_back = pvcc;
0423 atmvcc->push = pppoatm_push;
0424 atmvcc->pop = pppoatm_pop;
0425 atmvcc->release_cb = pppoatm_release_cb;
0426 __module_get(THIS_MODULE);
0427 atmvcc->owner = THIS_MODULE;
0428
0429
0430
0431 vcc_process_recv_queue(atmvcc);
0432 return 0;
0433 }
0434
0435
0436
0437
0438
0439 static int pppoatm_ioctl(struct socket *sock, unsigned int cmd,
0440 unsigned long arg)
0441 {
0442 struct atm_vcc *atmvcc = ATM_SD(sock);
0443 void __user *argp = (void __user *)arg;
0444
0445 if (cmd != ATM_SETBACKEND && atmvcc->push != pppoatm_push)
0446 return -ENOIOCTLCMD;
0447 switch (cmd) {
0448 case ATM_SETBACKEND: {
0449 atm_backend_t b;
0450 if (get_user(b, (atm_backend_t __user *) argp))
0451 return -EFAULT;
0452 if (b != ATM_BACKEND_PPP)
0453 return -ENOIOCTLCMD;
0454 if (!capable(CAP_NET_ADMIN))
0455 return -EPERM;
0456 if (sock->state != SS_CONNECTED)
0457 return -EINVAL;
0458 return pppoatm_assign_vcc(atmvcc, argp);
0459 }
0460 case PPPIOCGCHAN:
0461 return put_user(ppp_channel_index(&atmvcc_to_pvcc(atmvcc)->
0462 chan), (int __user *) argp) ? -EFAULT : 0;
0463 case PPPIOCGUNIT:
0464 return put_user(ppp_unit_number(&atmvcc_to_pvcc(atmvcc)->
0465 chan), (int __user *) argp) ? -EFAULT : 0;
0466 }
0467 return -ENOIOCTLCMD;
0468 }
0469
0470 static struct atm_ioctl pppoatm_ioctl_ops = {
0471 .owner = THIS_MODULE,
0472 .ioctl = pppoatm_ioctl,
0473 };
0474
0475 static int __init pppoatm_init(void)
0476 {
0477 register_atm_ioctl(&pppoatm_ioctl_ops);
0478 return 0;
0479 }
0480
0481 static void __exit pppoatm_exit(void)
0482 {
0483 deregister_atm_ioctl(&pppoatm_ioctl_ops);
0484 }
0485
0486 module_init(pppoatm_init);
0487 module_exit(pppoatm_exit);
0488
0489 MODULE_AUTHOR("Mitchell Blank Jr <mitch@sfgoth.com>");
0490 MODULE_DESCRIPTION("RFC2364 PPP over ATM/AAL5");
0491 MODULE_LICENSE("GPL");