PPP

来源:互联网 发布:安卓控制电脑软件 编辑:程序博客网 时间:2024/05/17 01:49
/******************************************************************/
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);
}