// SPDX-License-Identifier: GPL-2.0-or-later /* net/atm/pppoatm.c - RFC2364 PPP over ATM/AAL5 */ /* Copyright 1999-2000 by Mitchell Blank Jr */ /* Based on clip.c; 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ /* And on ppp_async.c; Copyright 1999 Paul Mackerras */ /* And help from Jens Axboe */ /* * * This driver provides the encapsulation and framing for sending * and receiving PPP frames in ATM AAL5 PDUs. */ /* * One shortcoming of this driver is that it does not comply with * section 8 of RFC2364 - we are supposed to detect a change * in encapsulation and immediately abort the connection (in order * to avoid a black-hole being created if our peer loses state * and changes encapsulation unilaterally. However, since the * ppp_generic layer actually does the decapsulation, we need * a way of notifying it when we _think_ there might be a problem) * There's two cases: * 1. LLC-encapsulation was missing when it was enabled. In * this case, we should tell the upper layer "tear down * this session if this skb looks ok to you" * 2. LLC-encapsulation was present when it was disabled. Then * we need to tell the upper layer "this packet may be * ok, but if its in error tear down the session" * These hooks are not yet available in ppp_generic */ #define pr_fmt(fmt) … #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/skbuff.h> #include <linux/slab.h> #include <linux/atm.h> #include <linux/atmdev.h> #include <linux/capability.h> #include <linux/ppp_defs.h> #include <linux/ppp-ioctl.h> #include <linux/ppp_channel.h> #include <linux/atmppp.h> #include "common.h" enum pppoatm_encaps { … }; struct pppoatm_vcc { … }; /* * We want to allow two packets in the queue. The one that's currently in * flight, and *one* queued up ready for the ATM device to send immediately * from its TX done IRQ. We want to be able to use atomic_inc_not_zero(), so * inflight == -2 represents an empty queue, -1 one packet, and zero means * there are two packets in the queue. */ #define NONE_INFLIGHT … #define BLOCKED … /* * Header used for LLC Encapsulated PPP (4 bytes) followed by the LCP protocol * ID (0xC021) used in autodetection */ static const unsigned char pppllc[6] = …; #define LLC_LEN … static inline struct pppoatm_vcc *atmvcc_to_pvcc(const struct atm_vcc *atmvcc) { … } static inline struct pppoatm_vcc *chan_to_pvcc(const struct ppp_channel *chan) { … } /* * We can't do this directly from our _pop handler, since the ppp code * doesn't want to be called in interrupt context, so we do it from * a tasklet */ static void pppoatm_wakeup_sender(struct tasklet_struct *t) { … } static void pppoatm_release_cb(struct atm_vcc *atmvcc) { … } /* * This gets called every time the ATM card has finished sending our * skb. The ->old_pop will take care up normal atm flow control, * but we also need to wake up the device if we blocked it */ static void pppoatm_pop(struct atm_vcc *atmvcc, struct sk_buff *skb) { … } /* * Unbind from PPP - currently we only do this when closing the socket, * but we could put this into an ioctl if need be */ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc) { … } /* Called when an AAL5 PDU comes in */ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) { … } static int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size) { … } /* * Called by the ppp_generic.c to send a packet - returns true if packet * was accepted. If we return false, then it's our job to call * ppp_output_wakeup(chan) when we're feeling more up to it. * Note that in the ENOMEM case (as opposed to the !atm_may_send case) * we should really drop the packet, but the generic layer doesn't * support this yet. We just return 'DROP_PACKET' which we actually define * as success, just to be clear what we're really doing. */ #define DROP_PACKET … static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) { … } /* This handles ioctls sent to the /dev/ppp interface */ static int pppoatm_devppp_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg) { … } static const struct ppp_channel_ops pppoatm_ops = …; static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg) { … } /* * This handles ioctls actually performed on our vcc - we must return * -ENOIOCTLCMD for any unrecognized ioctl */ static int pppoatm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { … } static struct atm_ioctl pppoatm_ioctl_ops = …; static int __init pppoatm_init(void) { … } static void __exit pppoatm_exit(void) { … } module_init(…) …; module_exit(pppoatm_exit); MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;