aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf/file.c
blob: bb40d63f328fa12b9da2b6cae5f6921d81797c72 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*
 * file.c
 *
 * PURPOSE
 *  File handling routines for the OSTA-UDF(tm) filesystem.
 *
 * CONTACTS
 *  E-mail regarding any portion of the Linux UDF file system should be
 *  directed to the development team mailing list (run by majordomo):
 *    linux_udf@hpesjro.fc.hp.com
 *
 * COPYRIGHT
 *  This file is distributed under the terms of the GNU General Public
 *  License (GPL). Copies of the GPL can be obtained from:
 *    ftp://prep.ai.mit.edu/pub/gnu/GPL
 *  Each contributing author retains all rights to their own work.
 *
 *  (C) 1998-1999 Dave Boynton
 *  (C) 1998-2004 Ben Fennema
 *  (C) 1999-2000 Stelias Computing Inc
 *
 * HISTORY
 *
 *  10/02/98 dgb  Attempt to integrate into udf.o
 *  10/07/98      Switched to using generic_readpage, etc., like isofs
 *                And it works!
 *  12/06/98 blf  Added udf_file_read. uses generic_file_read for all cases but
 *                ICBTAG_FLAG_AD_IN_ICB.
 *  04/06/99      64 bit file handling on 32 bit systems taken from ext2 file.c
 *  05/12/99      Preliminary file write support
 */

#include "udfdecl.h"
#include <linux/fs.h>
#include <linux/udf_fs.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/string.h> /* memset */
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>

#include "udf_i.h"
#include "udf_sb.h"

static int udf_adinicb_readpage(struct file *file, struct page * page)
{
	struct inode *inode = page->mapping->host;
	char *kaddr;

	BUG_ON(!PageLocked(page));

	kaddr = kmap(page);
	memset(kaddr, 0, PAGE_CACHE_SIZE);
	memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), inode->i_size);
	flush_dcache_page(page);
	SetPageUptodate(page);
	kunmap(page);
	unlock_page(page);
	return 0;
}

static int udf_adinicb_writepage(struct page *page, struct writeback_control *wbc)
{
	struct inode *inode = page->mapping->host;
	char *kaddr;

	BUG_ON(!PageLocked(page));

	kaddr = kmap(page);
	memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size);
	mark_inode_dirty(inode);
	SetPageUptodate(page);
	kunmap(page);
	unlock_page(page);
	return 0;
}

static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
	kmap(page);
	return 0;
}

static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
	struct inode *inode = page->mapping->host;
	char *kaddr = page_address(page);

	memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset,
		kaddr + offset, to - offset);
	mark_inode_dirty(inode);
	SetPageUptodate(page);
	kunmap(page);
	/* only one page here */
	if (to > inode->i_size)
		inode->i_size = to;
	return 0;
}

struct address_space_operations udf_adinicb_aops = {
	.readpage		= udf_adinicb_readpage,
	.writepage		= udf_adinicb_writepage,
	.sync_page		= block_sync_page,
	.prepare_write		= udf_adinicb_prepare_write,
	.commit_write		= udf_adinicb_commit_write,
};

static ssize_t udf_file_write(struct file * file, const char __user * buf,
	size_t count, loff_t *ppos)
{
	ssize_t retval;
	struct inode *inode = file->f_dentry->d_inode;
	int err, pos;

	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
	{
		if (file->f_flags & O_APPEND)
			pos = inode->i_size;
		else
			pos = *ppos;

		if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
			pos + count))
		{
			udf_expand_file_adinicb(inode, pos + count, &err);
			if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
			{
				udf_debug("udf_expand_adinicb: err=%d\n", err);
				return err;
			}
		}
		else
		{
			if (pos + count > inode->i_size)
				UDF_I_LENALLOC(inode) = pos + count;
			else
				UDF_I_LENALLOC(inode) = inode->i_size;
		}
	}

	retval = generic_file_write(file, buf, count, ppos);

	if (retval > 0)
		mark_inode_dirty(inode);
	return retval;
}

/*
 * udf_ioctl
 *
 * PURPOSE
 *	Issue an ioctl.
 *
 * DESCRIPTION
 *	Optional - sys_ioctl() will return -ENOTTY if this routine is not
 *	available, and the ioctl cannot be handled without filesystem help.
 *
 *	sys_ioctl() handles these ioctls that apply only to regular files:
 *		FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD
 *	These ioctls are also handled by sys_ioctl():
 *		FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC
 *	All other ioctls are passed to the filesystem.
 *
 *	Refer to sys_ioctl() in fs/ioctl.c
 *	sys_ioctl() -> .
 *
 * PRE-CONDITIONS
 *	inode			Pointer to inode that ioctl was issued on.
 *	filp			Pointer to file that ioctl was issued on.
 *	cmd			The ioctl command.
 *	arg			The ioctl argument [can be interpreted as a
 *				user-space pointer if desired].
 *
 * POST-CONDITIONS
 *	<return>		Success (>=0) or an error code (<=0) that
 *				sys_ioctl() will return.
 *
 * HISTORY
 *	July 1, 1997 - Andrew E. Mileski
 *	Written, tested, and released.
 */
int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
	unsigned long arg)
{
	int result = -EINVAL;

	if ( permission(inode, MAY_READ, NULL) != 0 )
	{
		udf_debug("no permission to access inode %lu\n",
						inode->i_ino);
		return -EPERM;
	}

	if ( !arg )
	{
		udf_debug("invalid argument to udf_ioctl\n");
		return -EINVAL;
	}

	switch (cmd)
	{
		case UDF_GETVOLIDENT:
			return copy_to_user((char __user *)arg,
				UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
		case UDF_RELOCATE_BLOCKS:
		{
			long old, new;

			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
			if (get_user(old, (long __user *)arg)) return -EFAULT;
			if ((result = udf_relocate_blocks(inode->i_sb,
					old, &new)) == 0)
				result = put_user(new, (long __user *)arg);

			return result;
		}
		case UDF_GETEASIZE:
			result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg);
			break;

		case UDF_GETEABLOCK:
			result = copy_to_user((char __user *)arg, UDF_I_DATA(inode),
				UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
			break;
	}

	return result;
}

/*
 * udf_release_file
 *
 * PURPOSE
 *  Called when all references to the file are closed
 *
 * DESCRIPTION
 *  Discard prealloced blocks
 *
 * HISTORY
 *
 */
static int udf_release_file(struct inode * inode, struct file * filp)
{
	if (filp->f_mode & FMODE_WRITE)
	{
		lock_kernel();
		udf_discard_prealloc(inode);
		unlock_kernel();
	}
	return 0;
}

struct file_operations udf_file_operations = {
	.read			= generic_file_read,
	.ioctl			= udf_ioctl,
	.open			= generic_file_open,
	.mmap			= generic_file_mmap,
	.write			= udf_file_write,
	.release		= udf_release_file,
	.fsync			= udf_fsync_file,
	.sendfile		= generic_file_sendfile,
};

struct inode_operations udf_file_inode_operations = {
	.truncate		= udf_truncate,
};
a> 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
/*
 * PPP async serial channel driver for Linux.
 *
 * Copyright 1999 Paul Mackerras.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version
 *  2 of the License, or (at your option) any later version.
 *
 * This driver provides the encapsulation and framing for sending
 * and receiving PPP frames over async serial lines.  It relies on
 * the generic PPP layer to give it frames to send and to process
 * received frames.  It implements the PPP line discipline.
 *
 * Part of the code in this driver was inspired by the old async-only
 * PPP driver, written by Michael Callahan and Al Longyear, and
 * subsequently hacked by Paul Mackerras.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/tty.h>
#include <linux/netdevice.h>
#include <linux/poll.h>
#include <linux/crc-ccitt.h>
#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
#include <linux/ppp_channel.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/string.h>

#define PPP_VERSION	"2.4.2"

#define OBUFSIZE	256

/* 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];
};

/* Bit numbers in xmit_flags */
#define XMIT_WAKEUP	0
#define XMIT_FULL	1
#define XMIT_BUSY	2

/* State bits */
#define SC_TOSS		1
#define SC_ESCAPE	2
#define SC_PREV_ERROR	4

/* Bits in rbits */
#define SC_RCV_BITS	(SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)

static int flag_time = HZ;
module_param(flag_time, int, 0);
MODULE_PARM_DESC(flag_time, "ppp_async: interval between flagged packets (in clock ticks)");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_PPP);

/*
 * Prototypes.
 */
static int ppp_async_encode(struct asyncppp *ap);
static int ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb);
static int ppp_async_push(struct asyncppp *ap);
static void ppp_async_flush_output(struct asyncppp *ap);
static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
			    char *flags, int count);
static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd,
			   unsigned long arg);
static void ppp_async_process(unsigned long arg);

static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,
			   int len, int inbound);

static struct ppp_channel_ops async_ops = {
	ppp_async_send,
	ppp_async_ioctl
};

/*
 * Routines implementing the PPP line discipline.
 */

/*
 * We have a potential race on dereferencing tty->disc_data,
 * because the tty layer provides no locking at all - thus one
 * cpu could be running ppp_asynctty_receive while another
 * calls ppp_asynctty_close, which zeroes tty->disc_data and
 * frees the memory that ppp_asynctty_receive is using.  The best
 * way to fix this is to use a rwlock in the tty struct, but for now
 * we use a single global rwlock for all ttys in ppp line discipline.
 *
 * FIXME: this is no longer true. The _close path for the ldisc is 
 * now guaranteed to be sane. 
 */
static DEFINE_RWLOCK(disc_data_lock);

static struct asyncppp *ap_get(struct tty_struct *tty)
{
	struct asyncppp *ap;

	read_lock(&disc_data_lock);
	ap = tty->disc_data;
	if (ap != NULL)
		atomic_inc(&ap->refcnt);
	read_unlock(&disc_data_lock);
	return ap;
}

static void ap_put(struct asyncppp *ap)
{
	if (atomic_dec_and_test(&ap->refcnt))
		up(&ap->dead_sem);
}

/*
 * 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;

	err = -ENOMEM;
	ap = kmalloc(sizeof(*ap), GFP_KERNEL);
	if (ap == 0)
		goto out;

	/* initialize the asyncppp structure */
	memset(ap, 0, sizeof(*ap));
	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);
	init_MUTEX_LOCKED(&ap->dead_sem);

	ap->chan.private = ap;
	ap->chan.ops = &async_ops;
	ap->chan.mtu = PPP_MRU;
	err = ppp_register_channel(&ap->chan);
	if (err)
		goto out_free;

	tty->disc_data = ap;

	return 0;

 out_free:
	kfree(ap);
 out:
	return err;
}

/*
 * Called when the tty is put into another line discipline
 * or it hangs up.  We have to wait for any cpu currently
 * executing in any of the other ppp_asynctty_* routines to
 * finish before we can call ppp_unregister_channel and free
 * the asyncppp struct.  This routine must be called from
 * process context, not interrupt or softirq context.
 */
static void
ppp_asynctty_close(struct tty_struct *tty)
{
	struct asyncppp *ap;

	write_lock_irq(&disc_data_lock);
	ap = tty->disc_data;
	tty->disc_data = NULL;
	write_unlock_irq(&disc_data_lock);
	if (ap == 0)
		return;

	/*
	 * We have now ensured that nobody can start using ap from now
	 * on, but we have to wait for all existing users to finish.
	 * Note that ppp_unregister_channel ensures that no calls to
	 * our channel ops (i.e. ppp_async_send/ioctl) are in progress
	 * by the time it returns.
	 */
	if (!atomic_dec_and_test(&ap->refcnt))
		down(&ap->dead_sem);
	tasklet_kill(&ap->tsk);

	ppp_unregister_channel(&ap->chan);
	if (ap->rpkt != 0)
		kfree_skb(ap->rpkt);
	skb_queue_purge(&ap->rqueue);
	if (ap->tpkt != 0)
		kfree_skb(ap->tpkt);
	kfree(ap);
}

/*
 * Called on tty hangup in process context.
 *
 * Wait for I/O to driver to complete and unregister PPP channel.
 * This is already done by the close routine, so just call that.
 */
static int ppp_asynctty_hangup(struct tty_struct *tty)
{
	ppp_asynctty_close(tty);
	return 0;
}

/*
 * 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;
}

/*
 * Called in process context only. May be re-entered by multiple
 * ioctl calling threads.
 */
 
static int
ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
		   unsigned int cmd, unsigned long arg)
{
	struct asyncppp *ap = ap_get(tty);
	int err, val;
	int __user *p = (int __user *)arg;

	if (ap == 0)
		return -ENXIO;
	err = -EFAULT;
	switch (cmd) {
	case PPPIOCGCHAN:
		err = -ENXIO;
		if (ap == 0)
			break;
		err = -EFAULT;
		if (put_user(ppp_channel_index(&ap->chan), p))
			break;
		err = 0;
		break;

	case PPPIOCGUNIT:
		err = -ENXIO;
		if (ap == 0)
			break;
		err = -EFAULT;
		if (put_user(ppp_unit_number(&ap->chan), p))
			break;
		err = 0;
		break;

	case TCGETS:
	case TCGETA:
		err = n_tty_ioctl(tty, file, cmd, arg);
		break;

	case TCFLSH:
		/* flush our buffers and the serial port's buffer */
		if (arg == TCIOFLUSH || arg == TCOFLUSH)
			ppp_async_flush_output(ap);
		err = n_tty_ioctl(tty, file, cmd, arg);
		break;

	case FIONREAD:
		val = 0;
		if (put_user(val, p))
			break;
		err = 0;
		break;

	default:
		err = -ENOIOCTLCMD;
	}

	ap_put(ap);
	return err;
}

/* No kernel lock - fine */
static unsigned int
ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
{
	return 0;
}

static int
ppp_asynctty_room(struct tty_struct *tty)
{
	return 65535;
}

/*
 * This can now be called from hard interrupt level as well
 * as soft interrupt level or mainline.
 */
static void
ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
		  char *cflags, int count)
{
	struct asyncppp *ap = ap_get(tty);
	unsigned long flags;

	if (ap == 0)
		return;
	spin_lock_irqsave(&ap->recv_lock, flags);
	ppp_async_input(ap, buf, cflags, count);
	spin_unlock_irqrestore(&ap->recv_lock, flags);
	if (!skb_queue_empty(&ap->rqueue))
		tasklet_schedule(&ap->tsk);
	ap_put(ap);
	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
	    && tty->driver->unthrottle)
		tty->driver->unthrottle(tty);
}

static void
ppp_asynctty_wakeup(struct tty_struct *tty)
{
	struct asyncppp *ap = ap_get(tty);

	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
	if (ap == 0)
		return;
	set_bit(XMIT_WAKEUP, &ap->xmit_flags);
	tasklet_schedule(&ap->tsk);
	ap_put(ap);
}


static struct tty_ldisc 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_room = ppp_asynctty_room,
	.receive_buf = ppp_asynctty_receive,
	.write_wakeup = ppp_asynctty_wakeup,
};

static int __init
ppp_async_init(void)
{
	int err;

	err = tty_register_ldisc(N_PPP, &ppp_ldisc);
	if (err != 0)
		printk(KERN_ERR "PPP_async: error %d registering line disc.\n",
		       err);
	return err;
}

/*
 * The following routines provide the PPP channel interface.
 */
static int
ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
{
	struct asyncppp *ap = chan->private;
	void __user *argp = (void __user *)arg;
	int __user *p = argp;
	int err, val;
	u32 accm[8];

	err = -EFAULT;
	switch (cmd) {
	case PPPIOCGFLAGS:
		val = ap->flags | ap->rbits;
		if (put_user(val, p))
			break;
		err = 0;
		break;
	case PPPIOCSFLAGS:
		if (get_user(val, p))
			break;
		ap->flags = val & ~SC_RCV_BITS;
		spin_lock_irq(&ap->recv_lock);
		ap->rbits = val & SC_RCV_BITS;
		spin_unlock_irq(&ap->recv_lock);
		err = 0;
		break;

	case PPPIOCGASYNCMAP:
		if (put_user(ap->xaccm[0], (u32 __user *)argp))
			break;
		err = 0;
		break;
	case PPPIOCSASYNCMAP:
		if (get_user(ap->xaccm[0], (u32 __user *)argp))
			break;
		err = 0;
		break;

	case PPPIOCGRASYNCMAP:
		if (put_user(ap->raccm, (u32 __user *)argp))
			break;
		err = 0;
		break;
	case PPPIOCSRASYNCMAP:
		if (get_user(ap->raccm, (u32 __user *)argp))
			break;
		err = 0;
		break;

	case PPPIOCGXASYNCMAP:
		if (copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm)))
			break;
		err = 0;
		break;
	case PPPIOCSXASYNCMAP:
		if (copy_from_user(accm, argp, sizeof(accm)))
			break;
		accm[2] &= ~0x40000000U;	/* can't escape 0x5e */
		accm[3] |= 0x60000000U;		/* must escape 0x7d, 0x7e */
		memcpy(ap->xaccm, accm, sizeof(ap->xaccm));
		err = 0;
		break;

	case PPPIOCGMRU:
		if (put_user(ap->mru, p))
			break;
		err = 0;
		break;
	case PPPIOCSMRU:
		if (get_user(val, p))
			break;
		if (val < PPP_MRU)
			val = PPP_MRU;
		ap->mru = val;
		err = 0;
		break;

	default:
		err = -ENOTTY;
	}

	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);
}

/*
 * Procedures for encapsulation and framing.
 */

/*
 * Procedure to encode the data for async serial transmission.
 * Does octet stuffing (escaping), puts the address/control bytes
 * on if A/C compression is disabled, and does protocol compression.
 * Assumes ap->tpkt != 0 on entry.
 * Returns 1 if we finished the current frame, 0 otherwise.
 */

#define PUT_BYTE(ap, buf, c, islcp)	do {		\
	if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\
		*buf++ = PPP_ESCAPE;			\
		*buf++ = c ^ 0x20;			\
	} else						\
		*buf++ = c;				\
} while (0)

static int
ppp_async_encode(struct asyncppp *ap)
{
	int fcs, i, count, c, proto;
	unsigned char *buf, *buflim;
	unsigned char *data;
	int islcp;

	buf = ap->obuf;
	ap->olim = buf;
	ap->optr = buf;
	i = ap->tpkt_pos;
	data = ap->tpkt->data;
	count = ap->tpkt->len;
	fcs = ap->tfcs;
	proto = (data[0] << 8) + data[1];

	/*
	 * LCP packets with code values between 1 (configure-reqest)
	 * and 7 (code-reject) must be sent as though no options
	 * had been negotiated.
	 */
	islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;

	if (i == 0) {
		if (islcp)
			async_lcp_peek(ap, data, count, 0);

		/*
		 * Start of a new packet - insert the leading FLAG
		 * character if necessary.
		 */
		if (islcp || flag_time == 0
		    || jiffies - ap->last_xmit >= flag_time)
			*buf++ = PPP_FLAG;
		ap->last_xmit = jiffies;
		fcs = PPP_INITFCS;

		/*
		 * Put in the address/control bytes if necessary
		 */
		if ((ap->flags & SC_COMP_AC) == 0 || islcp) {
			PUT_BYTE(ap, buf, 0xff, islcp);
			fcs = PPP_FCS(fcs, 0xff);
			PUT_BYTE(ap, buf, 0x03, islcp);
			fcs = PPP_FCS(fcs, 0x03);
		}
	}

	/*
	 * Once we put in the last byte, we need to put in the FCS
	 * and closing flag, so make sure there is at least 7 bytes
	 * of free space in the output buffer.
	 */
	buflim = ap->obuf + OBUFSIZE - 6;
	while (i < count && buf < buflim) {
		c = data[i++];
		if (i == 1 && c == 0 && (ap->flags & SC_COMP_PROT))
			continue;	/* compress protocol field */
		fcs = PPP_FCS(fcs, c);
		PUT_BYTE(ap, buf, c, islcp);
	}

	if (i < count) {
		/*
		 * Remember where we are up to in this packet.
		 */
		ap->olim = buf;
		ap->tpkt_pos = i;
		ap->tfcs = fcs;
		return 0;
	}

	/*
	 * We have finished the packet.  Add the FCS and flag.
	 */
	fcs = ~fcs;
	c = fcs & 0xff;
	PUT_BYTE(ap, buf, c, islcp);
	c = (fcs >> 8) & 0xff;
	PUT_BYTE(ap, buf, c, islcp);
	*buf++ = PPP_FLAG;
	ap->olim = buf;

	kfree_skb(ap->tpkt);
	ap->tpkt = NULL;
	return 1;
}

/*
 * Transmit-side routines.
 */

/*
 * 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;
}

/*
 * Push as much data as possible out to the tty.
 */
static int
ppp_async_push(struct asyncppp *ap)
{
	int avail, sent, done = 0;
	struct tty_struct *tty = ap->tty;
	int tty_stuffed = 0;

	/*
	 * We can get called recursively here if the tty write
	 * function calls our wakeup function.  This can happen
	 * for example on a pty with both the master and slave
	 * set to PPP line discipline.
	 * We use the XMIT_BUSY bit to detect this and get out,
	 * leaving the XMIT_WAKEUP bit set to tell the other
	 * instance that it may now be able to write more now.
	 */
	if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags))
		return 0;
	spin_lock_bh(&ap->xmit_lock);
	for (;;) {
		if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags))
			tty_stuffed = 0;
		if (!tty_stuffed && ap->optr < ap->olim) {
			avail = ap->olim - ap->optr;
			set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
			sent = tty->driver->write(tty, ap->optr, avail);
			if (sent < 0)
				goto flush;	/* error, e.g. loss of CD */
			ap->optr += sent;
			if (sent < avail)
				tty_stuffed = 1;
			continue;
		}
		if (ap->optr >= ap->olim && ap->tpkt != 0) {
			if (ppp_async_encode(ap)) {
				/* finished processing ap->tpkt */
				clear_bit(XMIT_FULL, &ap->xmit_flags);
				done = 1;
			}
			continue;
		}
		/*
		 * We haven't made any progress this time around.
		 * Clear XMIT_BUSY to let other callers in, but
		 * after doing so we have to check if anyone set
		 * XMIT_WAKEUP since we last checked it.  If they
		 * did, we should try again to set XMIT_BUSY and go
		 * around again in case XMIT_BUSY was still set when
		 * the other caller tried.
		 */
		clear_bit(XMIT_BUSY, &ap->xmit_flags);
		/* any more work to do? if not, exit the loop */
		if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags)
		      || (!tty_stuffed && ap->tpkt != 0)))
			break;
		/* more work to do, see if we can do it now */
		if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags))
			break;
	}
	spin_unlock_bh(&ap->xmit_lock);
	return done;

flush:
	clear_bit(XMIT_BUSY, &ap->xmit_flags);
	if (ap->tpkt != 0) {
		kfree_skb(ap->tpkt);
		ap->tpkt = NULL;
		clear_bit(XMIT_FULL, &ap->xmit_flags);
		done = 1;
	}
	ap->optr = ap->olim;
	spin_unlock_bh(&ap->xmit_lock);
	return done;
}

/*
 * Flush output from our internal buffers.
 * Called for the TCFLSH ioctl. Can be entered in parallel
 * but this is covered by the xmit_lock.
 */
static void
ppp_async_flush_output(struct asyncppp *ap)
{
	int done = 0;

	spin_lock_bh(&ap->xmit_lock);
	ap->optr = ap->olim;
	if (ap->tpkt != NULL) {
		kfree_skb(ap->tpkt);
		ap->tpkt = NULL;
		clear_bit(XMIT_FULL, &ap->xmit_flags);
		done = 1;
	}
	spin_unlock_bh(&ap->xmit_lock);
	if (done)
		ppp_output_wakeup(&ap->chan);
}

/*
 * Receive-side routines.
 */

/* see how many ordinary chars there are at the start of buf */
static inline int
scan_ordinary(struct asyncppp *ap, const unsigned char *buf, int count)
{
	int i, c;

	for (i = 0; i < count; ++i) {
		c = buf[i];
		if (c == PPP_ESCAPE || c == PPP_FLAG
		    || (c < 0x20 && (ap->raccm & (1 << c)) != 0))
			break;
	}
	return i;
}

/* called when a flag is seen - do end-of-packet processing */
static void
process_input_packet(struct asyncppp *ap)
{
	struct sk_buff *skb;
	unsigned char *p;
	unsigned int len, fcs, proto;

	skb = ap->rpkt;
	if (ap->state & (SC_TOSS | SC_ESCAPE))
		goto err;

	if (skb == NULL)
		return;		/* 0-length packet */

	/* check the FCS */
	p = skb->data;
	len = skb->len;
	if (len < 3)
		goto err;	/* too short */
	fcs = PPP_INITFCS;
	for (; len > 0; --len)
		fcs = PPP_FCS(fcs, *p++);
	if (fcs != PPP_GOODFCS)
		goto err;	/* bad FCS */
	skb_trim(skb, skb->len - 2);

	/* check for address/control and protocol compression */
	p = skb->data;
	if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
		/* chop off address/control */
		if (skb->len < 3)
			goto err;
		p = skb_pull(skb, 2);
	}
	proto = p[0];
	if (proto & 1) {
		/* protocol is compressed */
		skb_push(skb, 1)[0] = 0;
	} else {
		if (skb->len < 2)
			goto err;
		proto = (proto << 8) + p[1];
		if (proto == PPP_LCP)
			async_lcp_peek(ap, p, skb->len, 1);
	}

	/* queue the frame to be processed */
	skb->cb[0] = ap->state;
	skb_queue_tail(&ap->rqueue, skb);
	ap->rpkt = NULL;
	ap->state = 0;
	return;

 err:
	/* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */
	ap->state = SC_PREV_ERROR;
	if (skb) {
		/* make skb appear as freshly allocated */
		skb_trim(skb, 0);
		skb_reserve(skb, - skb_headroom(skb));
	}
}

/* Called when the tty driver has data for us. Runs parallel with the
   other ldisc functions but will not be re-entered */

static void
ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
		char *flags, int count)
{
	struct sk_buff *skb;
	int c, i, j, n, s, f;
	unsigned char *sp;

	/* update bits used for 8-bit cleanness detection */
	if (~ap->rbits & SC_RCV_BITS) {
		s = 0;
		for (i = 0; i < count; ++i) {
			c = buf[i];
			if (flags != 0 && flags[i] != 0)
				continue;
			s |= (c & 0x80)? SC_RCV_B7_1: SC_RCV_B7_0;
			c = ((c >> 4) ^ c) & 0xf;
			s |= (0x6996 & (1 << c))? SC_RCV_ODDP: SC_RCV_EVNP;
		}
		ap->rbits |= s;
	}

	while (count > 0) {
		/* scan through and see how many chars we can do in bulk */
		if ((ap->state & SC_ESCAPE) && buf[0] == PPP_ESCAPE)
			n = 1;
		else
			n = scan_ordinary(ap, buf, count);

		f = 0;
		if (flags != 0 && (ap->state & SC_TOSS) == 0) {
			/* check the flags to see if any char had an error */
			for (j = 0; j < n; ++j)
				if ((f = flags[j]) != 0)
					break;
		}
		if (f != 0) {
			/* start tossing */
			ap->state |= SC_TOSS;

		} else if (n > 0 && (ap->state & SC_TOSS) == 0) {
			/* stuff the chars in the skb */
			skb = ap->rpkt;
			if (skb == 0) {
				skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
				if (skb == 0)
					goto nomem;
 				ap->rpkt = skb;
 			}
 			if (skb->len == 0) {
 				/* Try to get the payload 4-byte aligned.
 				 * This should match the
 				 * PPP_ALLSTATIONS/PPP_UI/compressed tests in
 				 * process_input_packet, but we do not have
 				 * enough chars here to test buf[1] and buf[2].
 				 */
				if (buf[0] != PPP_ALLSTATIONS)
					skb_reserve(skb, 2 + (buf[0] & 1));
			}
			if (n > skb_tailroom(skb)) {
				/* packet overflowed MRU */
				ap->state |= SC_TOSS;
			} else {
				sp = skb_put(skb, n);
				memcpy(sp, buf, n);
				if (ap->state & SC_ESCAPE) {
					sp[0] ^= 0x20;
					ap->state &= ~SC_ESCAPE;
				}
			}
		}

		if (n >= count)
			break;

		c = buf[n];
		if (flags != NULL && flags[n] != 0) {
			ap->state |= SC_TOSS;
		} else if (c == PPP_FLAG) {
			process_input_packet(ap);
		} else if (c == PPP_ESCAPE) {
			ap->state |= SC_ESCAPE;
		} else if (I_IXON(ap->tty)) {
			if (c == START_CHAR(ap->tty))
				start_tty(ap->tty);
			else if (c == STOP_CHAR(ap->tty))
				stop_tty(ap->tty);
		}
		/* otherwise it's a char in the recv ACCM */
		++n;

		buf += n;
		if (flags != 0)
			flags += n;
		count -= n;
	}
	return;

 nomem:
	printk(KERN_ERR "PPPasync: no memory (input pkt)\n");
	ap->state |= SC_TOSS;
}

/*
 * We look at LCP frames going past so that we can notice
 * and react to the LCP configure-ack from the peer.
 * In the situation where the peer has been sent a configure-ack
 * already, LCP is up once it has sent its configure-ack
 * so the immediately following packet can be sent with the
 * configured LCP options.  This allows us to process the following
 * packet correctly without pppd needing to respond quickly.
 *
 * We only respond to the received configure-ack if we have just
 * sent a configure-request, and the configure-ack contains the
 * same data (this is checked using a 16-bit crc of the data).
 */
#define CONFREQ		1	/* LCP code field values */
#define CONFACK		2
#define LCP_MRU		1	/* LCP option numbers */
#define LCP_ASYNCMAP	2

static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,
			   int len, int inbound)
{
	int dlen, fcs, i, code;
	u32 val;

	data += 2;		/* skip protocol bytes */
	len -= 2;
	if (len < 4)		/* 4 = code, ID, length */
		return;
	code = data[0];
	if (code != CONFACK && code != CONFREQ)
		return;
	dlen = (data[2] << 8) + data[3];
	if (len < dlen)
		return;		/* packet got truncated or length is bogus */

	if (code == (inbound? CONFACK: CONFREQ)) {
		/*
		 * sent confreq or received confack:
		 * calculate the crc of the data from the ID field on.
		 */
		fcs = PPP_INITFCS;
		for (i = 1; i < dlen; ++i)
			fcs = PPP_FCS(fcs, data[i]);

		if (!inbound) {
			/* outbound confreq - remember the crc for later */
			ap->lcp_fcs = fcs;
			return;
		}

		/* received confack, check the crc */
		fcs ^= ap->lcp_fcs;
		ap->lcp_fcs = -1;
		if (fcs != 0)
			return;
	} else if (inbound)
		return;	/* not interested in received confreq */

	/* process the options in the confack */
	data += 4;
	dlen -= 4;
	/* data[0] is code, data[1] is length */
	while (dlen >= 2 && dlen >= data[1] && data[1] >= 2) {
		switch (data[0]) {
		case LCP_MRU:
			val = (data[2] << 8) + data[3];
			if (inbound)
				ap->mru = val;
			else
				ap->chan.mtu = val;
			break;
		case LCP_ASYNCMAP:
			val = (data[2] << 24) + (data[3] << 16)
				+ (data[4] << 8) + data[5];
			if (inbound)
				ap->raccm = val;
			else
				ap->xaccm[0] = val;
			break;
		}
		dlen -= data[1];
		data += data[1];
	}
}

static void __exit ppp_async_cleanup(void)
{
	if (tty_unregister_ldisc(N_PPP) != 0)
		printk(KERN_ERR "failed to unregister PPP line discipline\n");
}

module_init(ppp_async_init);
module_exit(ppp_async_cleanup);