/******************************************************************/
module_init(ppp_async_init);
static int __init
ppp_async_init(void)
{
tty_register_ldisc(N_PPP, &ppp_ldisc);
}
static struct tty_ldisc_ops ppp_ldisc = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
.name = "ppp",
.open = ppp_asynctty_open,
.close = ppp_asynctty_close,
.hangup = ppp_asynctty_hangup,
.read = ppp_asynctty_read,
.write = ppp_asynctty_write,
.ioctl = ppp_asynctty_ioctl,
.poll = ppp_asynctty_poll,
.receive_buf = ppp_asynctty_receive,
.write_wakeup = ppp_asynctty_wakeup,
};
/*行规的magic and tty magic*/
#define TTY_LDISC_MAGIC 0x5403
/* tty magic number */
#define TTY_MAGIC 0x5401
/* line disciplines */
#define N_TTY 0
#define N_SLIP 1
#define N_MOUSE 2
#define N_PPP 3
/*
* Read does nothing - no data is ever available this way.
* Pppd reads and writes packets via /dev/ppp instead.
*/
static ssize_t
ppp_asynctty_read(struct tty_struct *tty, struct file *file,
unsigned char __user *buf, size_t count)
{
return -EAGAIN;
}
/*
* Write on the tty does nothing, the packets all come in
* from the ppp generic stuff.
*/
static ssize_t
ppp_asynctty_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t count)
{
return -EAGAIN;
}
/*read/write是怎样实现的?从 open看看*/
/*核心数据结构是asyncppp
*Structure for storing local state.
**/
struct asyncppp {
struct tty_struct *tty;
unsigned int flags;
unsigned int state;
unsigned int rbits;
int mru;
spinlock_t xmit_lock;
spinlock_t recv_lock;
unsigned long xmit_flags;
u32 xaccm[8];
u32 raccm;
unsigned int bytes_sent;
unsigned int bytes_rcvd;
struct sk_buff *tpkt;
int tpkt_pos;
u16 tfcs;
unsigned char *optr;
unsigned char *olim;
unsigned long last_xmit;
struct sk_buff *rpkt;
int lcp_fcs;
struct sk_buff_head rqueue;
struct tasklet_struct tsk;
atomic_t refcnt;
struct semaphore dead_sem;
struct ppp_channel chan; /* interface to generic ppp layer */
unsigned char obuf[OBUFSIZE];
};
/*这里的channel又是什么用途*/
struct ppp_channel {
void *private; /* channel private data */
const struct ppp_channel_ops *ops; /* operations for this channel */
int mtu; /* max transmit packet size */
int hdrlen; /* amount of headroom channel needs */
void *ppp; /* opaque to channel */
int speed; /* transfer rate (bytes/second) */
/* the following is not used at present */
int latency; /* overhead time in milliseconds */
};
struct ppp_channel_ops {
/* Send a packet (or multilink fragment) on this channel.
Returns 1 if it was accepted, 0 if not. */
int (*start_xmit)(struct ppp_channel *, struct sk_buff *);
/* Handle an ioctl call that has come in via /dev/ppp. */
int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
};
/*
* Called when a tty is put into PPP line discipline. Called in process
* context.
*/
static int
ppp_asynctty_open(struct tty_struct *tty)
{
struct asyncppp *ap;
int err;
int speed;
/*这里是tty_ops不是file_operations*/
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
err = -ENOMEM;
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
if (!ap)
goto out;
/* initialize the asyncppp structure */
ap->tty = tty;
ap->mru = PPP_MRU;
spin_lock_init(&ap->xmit_lock);
spin_lock_init(&ap->recv_lock);
ap->xaccm[0] = ~0U;
ap->xaccm[3] = 0x60000000U;
ap->raccm = ~0U;
ap->optr = ap->obuf;
ap->olim = ap->obuf;
ap->lcp_fcs = -1;
skb_queue_head_init(&ap->rqueue);
tasklet_init(&ap->tsk, ppp_async_process, (unsigned long) ap);
atomic_set(&ap->refcnt, 1);
sema_init(&ap->dead_sem, 0);
ap->chan.private = ap;
ap->chan.ops = &async_ops;
ap->chan.mtu = PPP_MRU;
speed = tty_get_baud_rate(tty);
ap->chan.speed = speed;
err = ppp_register_channel(&ap->chan);
if (err)
goto out_free;
tty->disc_data = ap;
tty->receive_room = 65536;
return 0;
out_free:
kfree(ap);
out:
return err;
}
/*
* This is called at softirq level to deliver received packets
* to the ppp_generic code, and to tell the ppp_generic code
* if we can accept more output now.
*/
static void ppp_async_process(unsigned long arg)
{
struct asyncppp *ap = (struct asyncppp *) arg;
struct sk_buff *skb;
/* process received packets */
while ((skb = skb_dequeue(&ap->rqueue)) != NULL) {
if (skb->cb[0])
ppp_input_error(&ap->chan, 0);
ppp_input(&ap->chan, skb);
}
/* try to push more stuff out */
if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_async_push(ap))
ppp_output_wakeup(&ap->chan);
}
/*
* Send a packet to the peer over an async tty line.
* Returns 1 iff the packet was accepted.
* If the packet was not accepted, we will call ppp_output_wakeup
* at some later time.
*/
static int
ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb)
{
struct asyncppp *ap = chan->private;
ppp_async_push(ap);
if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags))
return 0; /* already full */
ap->tpkt = skb;
ap->tpkt_pos = 0;
ppp_async_push(ap);
return 1;
}
/* Create a new, unattached ppp channel. */
int ppp_register_channel(struct ppp_channel *chan)
{
return ppp_register_net_channel(current->nsproxy->net_ns, chan);
}