brintos

brintos / linux-shallow public Read only

0
0
Text · 16.3 KiB · 644e99f Raw
730 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * PPP synchronous tty channel driver for Linux.4 *5 * This is a ppp channel driver that can be used with tty device drivers6 * that are frame oriented, such as synchronous HDLC devices.7 *8 * Complete PPP frames without encoding/decoding are exchanged between9 * the channel driver and the device driver.10 *11 * The async map IOCTL codes are implemented to keep the user mode12 * applications happy if they call them. Synchronous PPP does not use13 * the async maps.14 *15 * Copyright 1999 Paul Mackerras.16 *17 * Also touched by the grubby hands of Paul Fulghum paulkf@microgate.com18 *19 * This driver provides the encapsulation and framing for sending20 * and receiving PPP frames over sync serial lines.  It relies on21 * the generic PPP layer to give it frames to send and to process22 * received frames.  It implements the PPP line discipline.23 *24 * Part of the code in this driver was inspired by the old async-only25 * PPP driver, written by Michael Callahan and Al Longyear, and26 * subsequently hacked by Paul Mackerras.27 *28 * ==FILEVERSION 20040616==29 */30 31#include <linux/module.h>32#include <linux/kernel.h>33#include <linux/skbuff.h>34#include <linux/tty.h>35#include <linux/netdevice.h>36#include <linux/poll.h>37#include <linux/ppp_defs.h>38#include <linux/ppp-ioctl.h>39#include <linux/ppp_channel.h>40#include <linux/spinlock.h>41#include <linux/completion.h>42#include <linux/init.h>43#include <linux/interrupt.h>44#include <linux/slab.h>45#include <linux/refcount.h>46#include <linux/unaligned.h>47#include <linux/uaccess.h>48 49#define PPP_VERSION	"2.4.2"50 51/* Structure for storing local state. */52struct syncppp {53	struct tty_struct *tty;54	unsigned int	flags;55	unsigned int	rbits;56	int		mru;57	spinlock_t	xmit_lock;58	spinlock_t	recv_lock;59	unsigned long	xmit_flags;60	u32		xaccm[8];61	u32		raccm;62	unsigned int	bytes_sent;63	unsigned int	bytes_rcvd;64 65	struct sk_buff	*tpkt;66	unsigned long	last_xmit;67 68	struct sk_buff_head rqueue;69 70	struct tasklet_struct tsk;71 72	refcount_t	refcnt;73	struct completion dead_cmp;74	struct ppp_channel chan;	/* interface to generic ppp layer */75};76 77/* Bit numbers in xmit_flags */78#define XMIT_WAKEUP	079#define XMIT_FULL	180 81/* Bits in rbits */82#define SC_RCV_BITS	(SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)83 84#define PPPSYNC_MAX_RQLEN	32	/* arbitrary */85 86/*87 * Prototypes.88 */89static struct sk_buff* ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *);90static int ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb);91static int ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd,92			  unsigned long arg);93static void ppp_sync_process(struct tasklet_struct *t);94static int ppp_sync_push(struct syncppp *ap);95static void ppp_sync_flush_output(struct syncppp *ap);96static void ppp_sync_input(struct syncppp *ap, const u8 *buf, const u8 *flags,97			   int count);98 99static const struct ppp_channel_ops sync_ops = {100	.start_xmit = ppp_sync_send,101	.ioctl      = ppp_sync_ioctl,102};103 104/*105 * Utility procedure to print a buffer in hex/ascii106 */107static void108ppp_print_buffer (const char *name, const __u8 *buf, int count)109{110	if (name != NULL)111		printk(KERN_DEBUG "ppp_synctty: %s, count = %d\n", name, count);112 113	print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, count);114}115 116 117/*118 * Routines implementing the synchronous PPP line discipline.119 */120 121/*122 * We have a potential race on dereferencing tty->disc_data,123 * because the tty layer provides no locking at all - thus one124 * cpu could be running ppp_synctty_receive while another125 * calls ppp_synctty_close, which zeroes tty->disc_data and126 * frees the memory that ppp_synctty_receive is using.  The best127 * way to fix this is to use a rwlock in the tty struct, but for now128 * we use a single global rwlock for all ttys in ppp line discipline.129 *130 * FIXME: Fixed in tty_io nowadays.131 */132static DEFINE_RWLOCK(disc_data_lock);133 134static struct syncppp *sp_get(struct tty_struct *tty)135{136	struct syncppp *ap;137 138	read_lock(&disc_data_lock);139	ap = tty->disc_data;140	if (ap != NULL)141		refcount_inc(&ap->refcnt);142	read_unlock(&disc_data_lock);143	return ap;144}145 146static void sp_put(struct syncppp *ap)147{148	if (refcount_dec_and_test(&ap->refcnt))149		complete(&ap->dead_cmp);150}151 152/*153 * Called when a tty is put into sync-PPP line discipline.154 */155static int156ppp_sync_open(struct tty_struct *tty)157{158	struct syncppp *ap;159	int err;160	int speed;161 162	if (tty->ops->write == NULL)163		return -EOPNOTSUPP;164 165	ap = kzalloc(sizeof(*ap), GFP_KERNEL);166	err = -ENOMEM;167	if (!ap)168		goto out;169 170	/* initialize the syncppp structure */171	ap->tty = tty;172	ap->mru = PPP_MRU;173	spin_lock_init(&ap->xmit_lock);174	spin_lock_init(&ap->recv_lock);175	ap->xaccm[0] = ~0U;176	ap->xaccm[3] = 0x60000000U;177	ap->raccm = ~0U;178 179	skb_queue_head_init(&ap->rqueue);180	tasklet_setup(&ap->tsk, ppp_sync_process);181 182	refcount_set(&ap->refcnt, 1);183	init_completion(&ap->dead_cmp);184 185	ap->chan.private = ap;186	ap->chan.ops = &sync_ops;187	ap->chan.mtu = PPP_MRU;188	ap->chan.hdrlen = 2;	/* for A/C bytes */189	speed = tty_get_baud_rate(tty);190	ap->chan.speed = speed;191	err = ppp_register_channel(&ap->chan);192	if (err)193		goto out_free;194 195	tty->disc_data = ap;196	tty->receive_room = 65536;197	return 0;198 199 out_free:200	kfree(ap);201 out:202	return err;203}204 205/*206 * Called when the tty is put into another line discipline207 * or it hangs up.  We have to wait for any cpu currently208 * executing in any of the other ppp_synctty_* routines to209 * finish before we can call ppp_unregister_channel and free210 * the syncppp struct.  This routine must be called from211 * process context, not interrupt or softirq context.212 */213static void214ppp_sync_close(struct tty_struct *tty)215{216	struct syncppp *ap;217 218	write_lock_irq(&disc_data_lock);219	ap = tty->disc_data;220	tty->disc_data = NULL;221	write_unlock_irq(&disc_data_lock);222	if (!ap)223		return;224 225	/*226	 * We have now ensured that nobody can start using ap from now227	 * on, but we have to wait for all existing users to finish.228	 * Note that ppp_unregister_channel ensures that no calls to229	 * our channel ops (i.e. ppp_sync_send/ioctl) are in progress230	 * by the time it returns.231	 */232	if (!refcount_dec_and_test(&ap->refcnt))233		wait_for_completion(&ap->dead_cmp);234	tasklet_kill(&ap->tsk);235 236	ppp_unregister_channel(&ap->chan);237	skb_queue_purge(&ap->rqueue);238	kfree_skb(ap->tpkt);239	kfree(ap);240}241 242/*243 * Called on tty hangup in process context.244 *245 * Wait for I/O to driver to complete and unregister PPP channel.246 * This is already done by the close routine, so just call that.247 */248static void ppp_sync_hangup(struct tty_struct *tty)249{250	ppp_sync_close(tty);251}252 253/*254 * Read does nothing - no data is ever available this way.255 * Pppd reads and writes packets via /dev/ppp instead.256 */257static ssize_t258ppp_sync_read(struct tty_struct *tty, struct file *file, u8 *buf, size_t count,259	      void **cookie, unsigned long offset)260{261	return -EAGAIN;262}263 264/*265 * Write on the tty does nothing, the packets all come in266 * from the ppp generic stuff.267 */268static ssize_t269ppp_sync_write(struct tty_struct *tty, struct file *file, const u8 *buf,270	       size_t count)271{272	return -EAGAIN;273}274 275static int276ppp_synctty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)277{278	struct syncppp *ap = sp_get(tty);279	int __user *p = (int __user *)arg;280	int err, val;281 282	if (!ap)283		return -ENXIO;284	err = -EFAULT;285	switch (cmd) {286	case PPPIOCGCHAN:287		err = -EFAULT;288		if (put_user(ppp_channel_index(&ap->chan), p))289			break;290		err = 0;291		break;292 293	case PPPIOCGUNIT:294		err = -EFAULT;295		if (put_user(ppp_unit_number(&ap->chan), p))296			break;297		err = 0;298		break;299 300	case TCFLSH:301		/* flush our buffers and the serial port's buffer */302		if (arg == TCIOFLUSH || arg == TCOFLUSH)303			ppp_sync_flush_output(ap);304		err = n_tty_ioctl_helper(tty, cmd, arg);305		break;306 307	case FIONREAD:308		val = 0;309		if (put_user(val, p))310			break;311		err = 0;312		break;313 314	default:315		err = tty_mode_ioctl(tty, cmd, arg);316		break;317	}318 319	sp_put(ap);320	return err;321}322 323/* May sleep, don't call from interrupt level or with interrupts disabled */324static void325ppp_sync_receive(struct tty_struct *tty, const u8 *buf, const u8 *cflags,326		 size_t count)327{328	struct syncppp *ap = sp_get(tty);329	unsigned long flags;330 331	if (!ap)332		return;333	spin_lock_irqsave(&ap->recv_lock, flags);334	ppp_sync_input(ap, buf, cflags, count);335	spin_unlock_irqrestore(&ap->recv_lock, flags);336	if (!skb_queue_empty(&ap->rqueue))337		tasklet_schedule(&ap->tsk);338	sp_put(ap);339	tty_unthrottle(tty);340}341 342static void343ppp_sync_wakeup(struct tty_struct *tty)344{345	struct syncppp *ap = sp_get(tty);346 347	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);348	if (!ap)349		return;350	set_bit(XMIT_WAKEUP, &ap->xmit_flags);351	tasklet_schedule(&ap->tsk);352	sp_put(ap);353}354 355 356static struct tty_ldisc_ops ppp_sync_ldisc = {357	.owner	= THIS_MODULE,358	.num	= N_SYNC_PPP,359	.name	= "pppsync",360	.open	= ppp_sync_open,361	.close	= ppp_sync_close,362	.hangup	= ppp_sync_hangup,363	.read	= ppp_sync_read,364	.write	= ppp_sync_write,365	.ioctl	= ppp_synctty_ioctl,366	.receive_buf = ppp_sync_receive,367	.write_wakeup = ppp_sync_wakeup,368};369 370static int __init371ppp_sync_init(void)372{373	int err;374 375	err = tty_register_ldisc(&ppp_sync_ldisc);376	if (err != 0)377		printk(KERN_ERR "PPP_sync: error %d registering line disc.\n",378		       err);379	return err;380}381 382/*383 * The following routines provide the PPP channel interface.384 */385static int386ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)387{388	struct syncppp *ap = chan->private;389	int err, val;390	u32 accm[8];391	void __user *argp = (void __user *)arg;392	u32 __user *p = argp;393 394	err = -EFAULT;395	switch (cmd) {396	case PPPIOCGFLAGS:397		val = ap->flags | ap->rbits;398		if (put_user(val, (int __user *) argp))399			break;400		err = 0;401		break;402	case PPPIOCSFLAGS:403		if (get_user(val, (int __user *) argp))404			break;405		ap->flags = val & ~SC_RCV_BITS;406		spin_lock_irq(&ap->recv_lock);407		ap->rbits = val & SC_RCV_BITS;408		spin_unlock_irq(&ap->recv_lock);409		err = 0;410		break;411 412	case PPPIOCGASYNCMAP:413		if (put_user(ap->xaccm[0], p))414			break;415		err = 0;416		break;417	case PPPIOCSASYNCMAP:418		if (get_user(ap->xaccm[0], p))419			break;420		err = 0;421		break;422 423	case PPPIOCGRASYNCMAP:424		if (put_user(ap->raccm, p))425			break;426		err = 0;427		break;428	case PPPIOCSRASYNCMAP:429		if (get_user(ap->raccm, p))430			break;431		err = 0;432		break;433 434	case PPPIOCGXASYNCMAP:435		if (copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm)))436			break;437		err = 0;438		break;439	case PPPIOCSXASYNCMAP:440		if (copy_from_user(accm, argp, sizeof(accm)))441			break;442		accm[2] &= ~0x40000000U;	/* can't escape 0x5e */443		accm[3] |= 0x60000000U;		/* must escape 0x7d, 0x7e */444		memcpy(ap->xaccm, accm, sizeof(ap->xaccm));445		err = 0;446		break;447 448	case PPPIOCGMRU:449		if (put_user(ap->mru, (int __user *) argp))450			break;451		err = 0;452		break;453	case PPPIOCSMRU:454		if (get_user(val, (int __user *) argp))455			break;456		if (val > U16_MAX) {457			err = -EINVAL;458			break;459		}460		if (val < PPP_MRU)461			val = PPP_MRU;462		ap->mru = val;463		err = 0;464		break;465 466	default:467		err = -ENOTTY;468	}469	return err;470}471 472/*473 * This is called at softirq level to deliver received packets474 * to the ppp_generic code, and to tell the ppp_generic code475 * if we can accept more output now.476 */477static void ppp_sync_process(struct tasklet_struct *t)478{479	struct syncppp *ap = from_tasklet(ap, t, tsk);480	struct sk_buff *skb;481 482	/* process received packets */483	while ((skb = skb_dequeue(&ap->rqueue)) != NULL) {484		if (skb->len == 0) {485			/* zero length buffers indicate error */486			ppp_input_error(&ap->chan, 0);487			kfree_skb(skb);488		}489		else490			ppp_input(&ap->chan, skb);491	}492 493	/* try to push more stuff out */494	if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_sync_push(ap))495		ppp_output_wakeup(&ap->chan);496}497 498/*499 * Procedures for encapsulation and framing.500 */501 502static struct sk_buff*503ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)504{505	int proto;506	unsigned char *data;507	int islcp;508 509	data  = skb->data;510	proto = get_unaligned_be16(data);511 512	/* LCP packets with codes between 1 (configure-request)513	 * and 7 (code-reject) must be sent as though no options514	 * have been negotiated.515	 */516	islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;517 518	/* compress protocol field if option enabled */519	if (data[0] == 0 && (ap->flags & SC_COMP_PROT) && !islcp)520		skb_pull(skb,1);521 522	/* prepend address/control fields if necessary */523	if ((ap->flags & SC_COMP_AC) == 0 || islcp) {524		if (skb_headroom(skb) < 2) {525			struct sk_buff *npkt = dev_alloc_skb(skb->len + 2);526			if (npkt == NULL) {527				kfree_skb(skb);528				return NULL;529			}530			skb_reserve(npkt,2);531			skb_copy_from_linear_data(skb,532				      skb_put(npkt, skb->len), skb->len);533			consume_skb(skb);534			skb = npkt;535		}536		skb_push(skb,2);537		skb->data[0] = PPP_ALLSTATIONS;538		skb->data[1] = PPP_UI;539	}540 541	ap->last_xmit = jiffies;542 543	if (skb && ap->flags & SC_LOG_OUTPKT)544		ppp_print_buffer ("send buffer", skb->data, skb->len);545 546	return skb;547}548 549/*550 * Transmit-side routines.551 */552 553/*554 * Send a packet to the peer over an sync tty line.555 * Returns 1 iff the packet was accepted.556 * If the packet was not accepted, we will call ppp_output_wakeup557 * at some later time.558 */559static int560ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb)561{562	struct syncppp *ap = chan->private;563 564	ppp_sync_push(ap);565 566	if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags))567		return 0;	/* already full */568	skb = ppp_sync_txmunge(ap, skb);569	if (skb != NULL)570		ap->tpkt = skb;571	else572		clear_bit(XMIT_FULL, &ap->xmit_flags);573 574	ppp_sync_push(ap);575	return 1;576}577 578/*579 * Push as much data as possible out to the tty.580 */581static int582ppp_sync_push(struct syncppp *ap)583{584	int sent, done = 0;585	struct tty_struct *tty = ap->tty;586	int tty_stuffed = 0;587 588	if (!spin_trylock_bh(&ap->xmit_lock))589		return 0;590	for (;;) {591		if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags))592			tty_stuffed = 0;593		if (!tty_stuffed && ap->tpkt) {594			set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);595			sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len);596			if (sent < 0)597				goto flush;	/* error, e.g. loss of CD */598			if (sent < ap->tpkt->len) {599				tty_stuffed = 1;600			} else {601				consume_skb(ap->tpkt);602				ap->tpkt = NULL;603				clear_bit(XMIT_FULL, &ap->xmit_flags);604				done = 1;605			}606			continue;607		}608		/* haven't made any progress */609		spin_unlock_bh(&ap->xmit_lock);610		if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) ||611		      (!tty_stuffed && ap->tpkt)))612			break;613		if (!spin_trylock_bh(&ap->xmit_lock))614			break;615	}616	return done;617 618flush:619	if (ap->tpkt) {620		kfree_skb(ap->tpkt);621		ap->tpkt = NULL;622		clear_bit(XMIT_FULL, &ap->xmit_flags);623		done = 1;624	}625	spin_unlock_bh(&ap->xmit_lock);626	return done;627}628 629/*630 * Flush output from our internal buffers.631 * Called for the TCFLSH ioctl.632 */633static void634ppp_sync_flush_output(struct syncppp *ap)635{636	int done = 0;637 638	spin_lock_bh(&ap->xmit_lock);639	if (ap->tpkt != NULL) {640		kfree_skb(ap->tpkt);641		ap->tpkt = NULL;642		clear_bit(XMIT_FULL, &ap->xmit_flags);643		done = 1;644	}645	spin_unlock_bh(&ap->xmit_lock);646	if (done)647		ppp_output_wakeup(&ap->chan);648}649 650/*651 * Receive-side routines.652 */653 654/* called when the tty driver has data for us.655 *656 * Data is frame oriented: each call to ppp_sync_input is considered657 * a whole frame. If the 1st flag byte is non-zero then the whole658 * frame is considered to be in error and is tossed.659 */660static void661ppp_sync_input(struct syncppp *ap, const u8 *buf, const u8 *flags, int count)662{663	struct sk_buff *skb;664	unsigned char *p;665 666	if (count == 0)667		return;668 669	if (ap->flags & SC_LOG_INPKT)670		ppp_print_buffer ("receive buffer", buf, count);671 672	/* stuff the chars in the skb */673	skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);674	if (!skb) {675		printk(KERN_ERR "PPPsync: no memory (input pkt)\n");676		goto err;677	}678	/* Try to get the payload 4-byte aligned */679	if (buf[0] != PPP_ALLSTATIONS)680		skb_reserve(skb, 2 + (buf[0] & 1));681 682	if (flags && *flags) {683		/* error flag set, ignore frame */684		goto err;685	} else if (count > skb_tailroom(skb)) {686		/* packet overflowed MRU */687		goto err;688	}689 690	skb_put_data(skb, buf, count);691 692	/* strip address/control field if present */693	p = skb->data;694	if (skb->len >= 2 && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {695		/* chop off address/control */696		if (skb->len < 3)697			goto err;698		p = skb_pull(skb, 2);699	}700 701	/* PPP packet length should be >= 2 bytes when protocol field is not702	 * compressed.703	 */704	if (!(p[0] & 0x01) && skb->len < 2)705		goto err;706 707	/* queue the frame to be processed */708	skb_queue_tail(&ap->rqueue, skb);709	return;710 711err:712	/* queue zero length packet as error indication */713	if (skb || (skb = dev_alloc_skb(0))) {714		skb_trim(skb, 0);715		skb_queue_tail(&ap->rqueue, skb);716	}717}718 719static void __exit720ppp_sync_cleanup(void)721{722	tty_unregister_ldisc(&ppp_sync_ldisc);723}724 725module_init(ppp_sync_init);726module_exit(ppp_sync_cleanup);727MODULE_DESCRIPTION("PPP synchronous TTY channel module");728MODULE_LICENSE("GPL");729MODULE_ALIAS_LDISC(N_SYNC_PPP);730