n_hdlc.c 22.2 KB
Newer Older
1
// SPDX-License-Identifier: GPL-1.0+
L
Linus Torvalds 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* generic HDLC line discipline for Linux
 *
 * Written by Paul Fulghum paulkf@microgate.com
 * for Microgate Corporation
 *
 * Microgate and SyncLink are registered trademarks of Microgate Corporation
 *
 * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
 *	Al Longyear <longyear@netcom.com>,
 *	Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
 *
 * Original release 01/11/99
 *
 * This module implements the tty line discipline N_HDLC for use with
 * tty device drivers that support bit-synchronous HDLC communications.
 *
 * All HDLC data is frame oriented which means:
 *
 * 1. tty write calls represent one complete transmit frame of data
21
 *    The device driver should accept the complete frame or none of
L
Linus Torvalds 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 *    the frame (busy) in the write method. Each write call should have
 *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
 *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
 *    should include any crc bytes required. For example, when using
 *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
 *    the application may transmit is limited to 65531 bytes. For CCITT
 *    CRC16, the maximum application frame size would be 65533.
 *
 *
 * 2. receive callbacks from the device driver represents
 *    one received frame. The device driver should bypass
 *    the tty flip buffer and call the line discipline receive
 *    callback directly to avoid fragmenting or concatenating
 *    multiple frames into a single receive callback.
 *
 *    The HDLC line discipline queues the receive frames in separate
 *    buffers so complete receive frames can be returned by the
 *    tty read calls.
 *
 * 3. tty read calls returns an entire frame of data or nothing.
42
 *
L
Linus Torvalds 已提交
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
 * 4. all send and receive data is considered raw. No processing
 *    or translation is performed by the line discipline, regardless
 *    of the tty flags
 *
 * 5. When line discipline is queried for the amount of receive
 *    data available (FIOC), 0 is returned if no data available,
 *    otherwise the count of the next available frame is returned.
 *    (instead of the sum of all received frame counts).
 *
 * These conventions allow the standard tty programming interface
 * to be used for synchronous HDLC applications when used with
 * this line discipline (or another line discipline that is frame
 * oriented such as N_PPP).
 *
 * The SyncLink driver (synclink.c) implements both asynchronous
 * (using standard line discipline N_TTY) and synchronous HDLC
 * (using N_HDLC) communications, with the latter using the above
 * conventions.
 *
 * This implementation is very basic and does not maintain
 * any statistics. The main point is to enforce the raw data
 * and frame orientation of HDLC communications.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define HDLC_MAGIC 0x239e

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>

#include <linux/poll.h>
#include <linux/in.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h>	/* used in new tty drivers */
#include <linux/signal.h>	/* used in new tty drivers */
#include <linux/if.h>
#include <linux/bitops.h>

#include <asm/termios.h>
102
#include <linux/uaccess.h>
103
#include "tty.h"
L
Linus Torvalds 已提交
104 105 106 107

/*
 * Buffers for individual HDLC frames
 */
108
#define MAX_HDLC_FRAME_SIZE 65535
L
Linus Torvalds 已提交
109 110
#define DEFAULT_RX_BUF_COUNT 10
#define MAX_RX_BUF_COUNT 60
P
Paul Fulghum 已提交
111
#define DEFAULT_TX_BUF_COUNT 3
L
Linus Torvalds 已提交
112 113

struct n_hdlc_buf {
114
	struct list_head  list_item;
L
Linus Torvalds 已提交
115
	int		  count;
116
	char		  buf[];
L
Linus Torvalds 已提交
117 118 119
};

struct n_hdlc_buf_list {
120
	struct list_head  list;
L
Linus Torvalds 已提交
121 122 123 124 125 126
	int		  count;
	spinlock_t	  spinlock;
};

/**
 * struct n_hdlc - per device instance data structure
J
Jiri Slaby 已提交
127 128 129 130 131 132 133
 * @magic: magic value for structure
 * @tbusy: reentrancy flag for tx wakeup code
 * @woke_up: tx wakeup needs to be run again as it was called while @tbusy
 * @tx_buf_list: list of pending transmit frame buffers
 * @rx_buf_list: list of received frame buffers
 * @tx_free_buf_list: list unused transmit frame buffers
 * @rx_free_buf_list: list unused received frame buffers
L
Linus Torvalds 已提交
134 135 136
 */
struct n_hdlc {
	int			magic;
137 138
	bool			tbusy;
	bool			woke_up;
L
Linus Torvalds 已提交
139 140 141 142 143 144 145 146 147
	struct n_hdlc_buf_list	tx_buf_list;
	struct n_hdlc_buf_list	rx_buf_list;
	struct n_hdlc_buf_list	tx_free_buf_list;
	struct n_hdlc_buf_list	rx_free_buf_list;
};

/*
 * HDLC buffer list manipulation functions
 */
148 149
static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
						struct n_hdlc_buf *buf);
L
Linus Torvalds 已提交
150 151 152 153 154 155
static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
			   struct n_hdlc_buf *buf);
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);

/* Local functions */

156
static struct n_hdlc *n_hdlc_alloc(void);
L
Linus Torvalds 已提交
157 158 159 160

/* max frame size for memory allocations */
static int maxframe = 4096;

P
Paul Fulghum 已提交
161 162
static void flush_rx_queue(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
163
	struct n_hdlc *n_hdlc = tty->disc_data;
P
Paul Fulghum 已提交
164 165 166 167 168 169 170 171
	struct n_hdlc_buf *buf;

	while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
}

static void flush_tx_queue(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
172
	struct n_hdlc *n_hdlc = tty->disc_data;
P
Paul Fulghum 已提交
173 174 175 176 177 178
	struct n_hdlc_buf *buf;

	while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
}

179 180 181 182 183 184 185 186 187 188
static void n_hdlc_free_buf_list(struct n_hdlc_buf_list *list)
{
	struct n_hdlc_buf *buf;

	do {
		buf = n_hdlc_buf_get(list);
		kfree(buf);
	} while (buf);
}

L
Linus Torvalds 已提交
189 190
/**
 * n_hdlc_tty_close - line discipline close
J
Jiri Slaby 已提交
191
 * @tty: pointer to tty info structure
L
Linus Torvalds 已提交
192 193 194 195 196 197
 *
 * Called when the line discipline is changed to something
 * else, the tty is closed, or the tty detects a hangup.
 */
static void n_hdlc_tty_close(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
198
	struct n_hdlc *n_hdlc = tty->disc_data;
L
Linus Torvalds 已提交
199

200
	if (n_hdlc->magic != HDLC_MAGIC) {
201
		pr_warn("n_hdlc: trying to close unopened tty!\n");
202 203
		return;
	}
L
Linus Torvalds 已提交
204
#if defined(TTY_NO_WRITE_SPLIT)
205
	clear_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
L
Linus Torvalds 已提交
206
#endif
207
	tty->disc_data = NULL;
J
Jiri Slaby 已提交
208 209 210 211 212 213 214 215 216 217

	/* Ensure that the n_hdlcd process is not hanging on select()/poll() */
	wake_up_interruptible(&tty->read_wait);
	wake_up_interruptible(&tty->write_wait);

	n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list);
	n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list);
	n_hdlc_free_buf_list(&n_hdlc->rx_buf_list);
	n_hdlc_free_buf_list(&n_hdlc->tx_buf_list);
	kfree(n_hdlc);
L
Linus Torvalds 已提交
218 219 220 221
}	/* end of n_hdlc_tty_close() */

/**
 * n_hdlc_tty_open - called when line discipline changed to n_hdlc
J
Jiri Slaby 已提交
222
 * @tty: pointer to tty info structure
L
Linus Torvalds 已提交
223 224 225
 *
 * Returns 0 if success, otherwise error code
 */
226
static int n_hdlc_tty_open(struct tty_struct *tty)
L
Linus Torvalds 已提交
227
{
J
Jiri Slaby 已提交
228
	struct n_hdlc *n_hdlc = tty->disc_data;
L
Linus Torvalds 已提交
229

230
	pr_debug("%s() called (device=%s)\n", __func__, tty->name);
231

L
Linus Torvalds 已提交
232 233
	/* There should not be an existing table for this slot. */
	if (n_hdlc) {
234
		pr_err("%s: tty already associated!\n", __func__);
L
Linus Torvalds 已提交
235 236
		return -EEXIST;
	}
237

L
Linus Torvalds 已提交
238 239
	n_hdlc = n_hdlc_alloc();
	if (!n_hdlc) {
240
		pr_err("%s: n_hdlc_alloc failed\n", __func__);
L
Linus Torvalds 已提交
241 242
		return -ENFILE;
	}
243

L
Linus Torvalds 已提交
244
	tty->disc_data = n_hdlc;
A
Alan Cox 已提交
245
	tty->receive_room = 65536;
246

L
Linus Torvalds 已提交
247
	/* change tty_io write() to not split large writes into 8K chunks */
248
	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
249

P
Paul Fulghum 已提交
250
	/* flush receive data from driver */
A
Alan Cox 已提交
251
	tty_driver_flush_buffer(tty);
J
Jiri Slaby 已提交
252

L
Linus Torvalds 已提交
253
	return 0;
254

L
Linus Torvalds 已提交
255 256 257 258
}	/* end of n_tty_hdlc_open() */

/**
 * n_hdlc_send_frames - send frames on pending send buffer list
J
Jiri Slaby 已提交
259 260
 * @n_hdlc: pointer to ldisc instance data
 * @tty: pointer to tty instance data
L
Linus Torvalds 已提交
261 262 263 264 265 266 267 268 269 270 271
 *
 * Send frames on pending send buffer list until the driver does not accept a
 * frame (busy) this function is called after adding a frame to the send buffer
 * list and by the tty wakeup callback.
 */
static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
{
	register int actual;
	unsigned long flags;
	struct n_hdlc_buf *tbuf;

272 273 274
check_again:

	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
L
Linus Torvalds 已提交
275
	if (n_hdlc->tbusy) {
276 277
		n_hdlc->woke_up = true;
		spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
L
Linus Torvalds 已提交
278 279
		return;
	}
280 281
	n_hdlc->tbusy = true;
	n_hdlc->woke_up = false;
L
Linus Torvalds 已提交
282 283
	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);

284
	tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
L
Linus Torvalds 已提交
285
	while (tbuf) {
286
		pr_debug("sending frame %p, count=%d\n", tbuf, tbuf->count);
287

L
Linus Torvalds 已提交
288
		/* Send the next block of data to device */
289
		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
A
Alan Cox 已提交
290
		actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
291 292 293

		/* rollback was possible and has been done */
		if (actual == -ERESTARTSYS) {
294
			n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
295 296
			break;
		}
L
Linus Torvalds 已提交
297 298 299 300
		/* if transmit error, throw frame away by */
		/* pretending it was accepted by driver */
		if (actual < 0)
			actual = tbuf->count;
301

L
Linus Torvalds 已提交
302
		if (actual == tbuf->count) {
303
			pr_debug("frame %p completed\n", tbuf);
304

L
Linus Torvalds 已提交
305 306
			/* free current transmit buffer */
			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
307

L
Linus Torvalds 已提交
308 309
			/* wait up sleeping writers */
			wake_up_interruptible(&tty->write_wait);
310

L
Linus Torvalds 已提交
311 312 313
			/* get next pending transmit buffer */
			tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
		} else {
314
			pr_debug("frame %p pending\n", tbuf);
315 316 317 318 319 320

			/*
			 * the buffer was not accepted by driver,
			 * return it back into tx queue
			 */
			n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
L
Linus Torvalds 已提交
321 322 323
			break;
		}
	}
324

L
Linus Torvalds 已提交
325
	if (!tbuf)
326
		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
327

L
Linus Torvalds 已提交
328 329
	/* Clear the re-entry flag */
	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
330
	n_hdlc->tbusy = false;
331 332 333 334
	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);

	if (n_hdlc->woke_up)
		goto check_again;
L
Linus Torvalds 已提交
335 336 337 338
}	/* end of n_hdlc_send_frames() */

/**
 * n_hdlc_tty_wakeup - Callback for transmit wakeup
J
Jiri Slaby 已提交
339
 * @tty: pointer to associated tty instance data
L
Linus Torvalds 已提交
340 341 342 343 344
 *
 * Called when low level device driver can accept more send data.
 */
static void n_hdlc_tty_wakeup(struct tty_struct *tty)
{
J
Jiri Slaby 已提交
345
	struct n_hdlc *n_hdlc = tty->disc_data;
L
Linus Torvalds 已提交
346

347
	n_hdlc_send_frames(n_hdlc, tty);
L
Linus Torvalds 已提交
348 349 350 351
}	/* end of n_hdlc_tty_wakeup() */

/**
 * n_hdlc_tty_receive - Called by tty driver when receive data is available
J
Jiri Slaby 已提交
352 353 354 355
 * @tty: pointer to tty instance data
 * @data: pointer to received data
 * @flags: pointer to flags for data
 * @count: count of received data in bytes
L
Linus Torvalds 已提交
356 357 358 359
 *
 * Called by tty low level driver when receive data is available. Data is
 * interpreted as one HDLC frame.
 */
360
static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
361
			       const char *flags, int count)
L
Linus Torvalds 已提交
362
{
J
Jiri Slaby 已提交
363
	register struct n_hdlc *n_hdlc = tty->disc_data;
L
Linus Torvalds 已提交
364 365
	register struct n_hdlc_buf *buf;

366
	pr_debug("%s() called count=%d\n", __func__, count);
367

L
Linus Torvalds 已提交
368 369
	/* verify line is using HDLC discipline */
	if (n_hdlc->magic != HDLC_MAGIC) {
370
		pr_err("line not using HDLC discipline\n");
371
		return;
L
Linus Torvalds 已提交
372
	}
373

374
	if (count > maxframe) {
375
		pr_debug("rx count>maxframesize, data discarded\n");
376
		return;
L
Linus Torvalds 已提交
377 378
	}

379
	/* get a free HDLC buffer */
L
Linus Torvalds 已提交
380 381
	buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
	if (!buf) {
J
Jiri Slaby 已提交
382 383 384 385
		/*
		 * no buffers in free list, attempt to allocate another rx
		 * buffer unless the maximum count has been reached
		 */
L
Linus Torvalds 已提交
386
		if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
387 388
			buf = kmalloc(struct_size(buf, buf, maxframe),
				      GFP_ATOMIC);
L
Linus Torvalds 已提交
389
	}
390

L
Linus Torvalds 已提交
391
	if (!buf) {
392
		pr_debug("no more rx buffers, data discarded\n");
393
		return;
L
Linus Torvalds 已提交
394
	}
395

L
Linus Torvalds 已提交
396
	/* copy received data to HDLC buffer */
397
	memcpy(buf->buf, data, count);
398
	buf->count = count;
L
Linus Torvalds 已提交
399 400 401

	/* add HDLC buffer to list of received frames */
	n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
402

L
Linus Torvalds 已提交
403
	/* wake up any blocked reads and perform async signalling */
404
	wake_up_interruptible(&tty->read_wait);
J
Jiri Slaby 已提交
405 406
	if (tty->fasync != NULL)
		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
L
Linus Torvalds 已提交
407 408 409 410

}	/* end of n_hdlc_tty_receive() */

/**
M
Matt Mackall 已提交
411
 * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
J
Jiri Slaby 已提交
412 413
 * @tty: pointer to tty instance data
 * @file: pointer to open file object
414
 * @kbuf: pointer to returned data buffer
J
Jiri Slaby 已提交
415
 * @nr: size of returned data buffer
416 417
 * @cookie: stored rbuf from previous run
 * @offset: offset into the data buffer
418
 *
L
Linus Torvalds 已提交
419 420 421
 * Returns the number of bytes returned or error code.
 */
static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
422 423
			   __u8 *kbuf, size_t nr,
			   void **cookie, unsigned long offset)
L
Linus Torvalds 已提交
424
{
J
Jiri Slaby 已提交
425
	struct n_hdlc *n_hdlc = tty->disc_data;
426
	int ret = 0;
L
Linus Torvalds 已提交
427
	struct n_hdlc_buf *rbuf;
428
	DECLARE_WAITQUEUE(wait, current);
L
Linus Torvalds 已提交
429

430 431 432 433 434
	/* Is this a repeated call for an rbuf we already found earlier? */
	rbuf = *cookie;
	if (rbuf)
		goto have_rbuf;

435
	add_wait_queue(&tty->read_wait, &wait);
A
Alan Cox 已提交
436

L
Linus Torvalds 已提交
437
	for (;;) {
438
		if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
439 440
			ret = -EIO;
			break;
A
Alan Cox 已提交
441
		}
442 443
		if (tty_hung_up_p(file))
			break;
L
Linus Torvalds 已提交
444

445
		set_current_state(TASK_INTERRUPTIBLE);
L
Linus Torvalds 已提交
446 447

		rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
448
		if (rbuf)
L
Linus Torvalds 已提交
449
			break;
450

L
Linus Torvalds 已提交
451
		/* no data */
452
		if (tty_io_nonblock(tty, file)) {
453 454
			ret = -EAGAIN;
			break;
A
Alan Cox 已提交
455
		}
456 457 458

		schedule();

A
Alan Cox 已提交
459
		if (signal_pending(current)) {
460 461
			ret = -EINTR;
			break;
A
Alan Cox 已提交
462
		}
L
Linus Torvalds 已提交
463
	}
464 465 466 467

	remove_wait_queue(&tty->read_wait, &wait);
	__set_current_state(TASK_RUNNING);

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
	if (!rbuf)
		return ret;
	*cookie = rbuf;

have_rbuf:
	/* Have we used it up entirely? */
	if (offset >= rbuf->count)
		goto done_with_rbuf;

	/* More data to go, but can't copy any more? EOVERFLOW */
	ret = -EOVERFLOW;
	if (!nr)
		goto done_with_rbuf;

	/* Copy as much data as possible */
	ret = rbuf->count - offset;
	if (ret > nr)
		ret = nr;
	memcpy(kbuf, rbuf->buf+offset, ret);
	offset += ret;

	/* If we still have data left, we leave the rbuf in the cookie */
	if (offset < rbuf->count)
		return ret;

done_with_rbuf:
	*cookie = NULL;

	if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
		kfree(rbuf);
	else
		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf);

L
Linus Torvalds 已提交
501
	return ret;
502

L
Linus Torvalds 已提交
503 504 505 506
}	/* end of n_hdlc_tty_read() */

/**
 * n_hdlc_tty_write - write a single frame of data to device
J
Jiri Slaby 已提交
507 508 509 510
 * @tty: pointer to associated tty device instance data
 * @file: pointer to file object data
 * @data: pointer to transmit data (one frame)
 * @count: size of transmit frame in bytes
511
 *
L
Linus Torvalds 已提交
512 513 514 515 516
 * Returns the number of bytes written (or error code).
 */
static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
			    const unsigned char *data, size_t count)
{
J
Jiri Slaby 已提交
517
	struct n_hdlc *n_hdlc = tty->disc_data;
L
Linus Torvalds 已提交
518 519 520 521
	int error = 0;
	DECLARE_WAITQUEUE(wait, current);
	struct n_hdlc_buf *tbuf;

522
	pr_debug("%s() called count=%zd\n", __func__, count);
523

L
Linus Torvalds 已提交
524 525 526 527
	if (n_hdlc->magic != HDLC_MAGIC)
		return -EIO;

	/* verify frame size */
528
	if (count > maxframe) {
529 530
		pr_debug("%s: truncating user packet from %zu to %d\n",
				__func__, count, maxframe);
L
Linus Torvalds 已提交
531 532
		count = maxframe;
	}
533

L
Linus Torvalds 已提交
534
	add_wait_queue(&tty->write_wait, &wait);
535 536 537

	for (;;) {
		set_current_state(TASK_INTERRUPTIBLE);
538

539 540 541 542
		tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
		if (tbuf)
			break;

543
		if (tty_io_nonblock(tty, file)) {
P
Paul Fulghum 已提交
544 545 546
			error = -EAGAIN;
			break;
		}
L
Linus Torvalds 已提交
547
		schedule();
J
Jiri Slaby 已提交
548

L
Linus Torvalds 已提交
549 550 551 552 553 554
		if (signal_pending(current)) {
			error = -EINTR;
			break;
		}
	}

555
	__set_current_state(TASK_RUNNING);
L
Linus Torvalds 已提交
556 557
	remove_wait_queue(&tty->write_wait, &wait);

558
	if (!error) {
L
Linus Torvalds 已提交
559 560 561 562 563
		/* Retrieve the user's buffer */
		memcpy(tbuf->buf, data, count);

		/* Send the data */
		tbuf->count = error = count;
564 565
		n_hdlc_buf_put(&n_hdlc->tx_buf_list, tbuf);
		n_hdlc_send_frames(n_hdlc, tty);
L
Linus Torvalds 已提交
566
	}
567

L
Linus Torvalds 已提交
568
	return error;
569

L
Linus Torvalds 已提交
570 571 572 573
}	/* end of n_hdlc_tty_write() */

/**
 * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
J
Jiri Slaby 已提交
574 575 576
 * @tty: pointer to tty instance data
 * @cmd: IOCTL command code
 * @arg: argument for IOCTL call (cmd dependent)
L
Linus Torvalds 已提交
577 578 579
 *
 * Returns command dependent result.
 */
580 581
static int n_hdlc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
			    unsigned long arg)
L
Linus Torvalds 已提交
582
{
J
Jiri Slaby 已提交
583
	struct n_hdlc *n_hdlc = tty->disc_data;
L
Linus Torvalds 已提交
584 585 586
	int error = 0;
	int count;
	unsigned long flags;
587 588
	struct n_hdlc_buf *buf = NULL;

589
	pr_debug("%s() called %d\n", __func__, cmd);
590

L
Linus Torvalds 已提交
591
	/* Verify the status of the device */
J
Jiri Slaby 已提交
592
	if (n_hdlc->magic != HDLC_MAGIC)
L
Linus Torvalds 已提交
593 594 595 596 597 598
		return -EBADF;

	switch (cmd) {
	case FIONREAD:
		/* report count of read data available */
		/* in next available frame (if any) */
599
		spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock, flags);
600 601 602 603
		buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
						struct n_hdlc_buf, list_item);
		if (buf)
			count = buf->count;
L
Linus Torvalds 已提交
604 605
		else
			count = 0;
606
		spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock, flags);
L
Linus Torvalds 已提交
607 608 609 610 611
		error = put_user(count, (int __user *)arg);
		break;

	case TIOCOUTQ:
		/* get the pending tx byte count in the driver */
A
Alan Cox 已提交
612
		count = tty_chars_in_buffer(tty);
L
Linus Torvalds 已提交
613
		/* add size of next output frame in queue */
614
		spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
615 616 617 618
		buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
						struct n_hdlc_buf, list_item);
		if (buf)
			count += buf->count;
619
		spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
L
Linus Torvalds 已提交
620 621 622
		error = put_user(count, (int __user *)arg);
		break;

P
Paul Fulghum 已提交
623 624 625 626 627 628
	case TCFLSH:
		switch (arg) {
		case TCIOFLUSH:
		case TCOFLUSH:
			flush_tx_queue(tty);
		}
629
		fallthrough;	/* to default */
P
Paul Fulghum 已提交
630

L
Linus Torvalds 已提交
631
	default:
632
		error = n_tty_ioctl_helper(tty, cmd, arg);
L
Linus Torvalds 已提交
633 634 635
		break;
	}
	return error;
636

L
Linus Torvalds 已提交
637 638 639 640
}	/* end of n_hdlc_tty_ioctl() */

/**
 * n_hdlc_tty_poll - TTY callback for poll system call
J
Jiri Slaby 已提交
641 642 643
 * @tty: pointer to tty instance data
 * @filp: pointer to open file object for device
 * @wait: wait queue for operations
644
 *
L
Linus Torvalds 已提交
645 646 647 648
 * Determine which operations (read/write) will not block and return info
 * to caller.
 * Returns a bit mask containing info on which ops will not block.
 */
649
static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
L
Linus Torvalds 已提交
650 651
				    poll_table *wait)
{
J
Jiri Slaby 已提交
652
	struct n_hdlc *n_hdlc = tty->disc_data;
653
	__poll_t mask = 0;
L
Linus Torvalds 已提交
654

J
Jiri Slaby 已提交
655
	if (n_hdlc->magic != HDLC_MAGIC)
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
		return 0;

	/*
	 * queue the current process into any wait queue that may awaken in the
	 * future (read and write)
	 */
	poll_wait(filp, &tty->read_wait, wait);
	poll_wait(filp, &tty->write_wait, wait);

	/* set bits for operations that won't block */
	if (!list_empty(&n_hdlc->rx_buf_list.list))
		mask |= EPOLLIN | EPOLLRDNORM;	/* readable */
	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
		mask |= EPOLLHUP;
	if (tty_hung_up_p(filp))
		mask |= EPOLLHUP;
	if (!tty_is_writelocked(tty) &&
			!list_empty(&n_hdlc->tx_free_buf_list.list))
		mask |= EPOLLOUT | EPOLLWRNORM;	/* writable */

L
Linus Torvalds 已提交
676 677 678
	return mask;
}	/* end of n_hdlc_tty_poll() */

679 680 681 682 683 684 685 686 687
static void n_hdlc_alloc_buf(struct n_hdlc_buf_list *list, unsigned int count,
		const char *name)
{
	struct n_hdlc_buf *buf;
	unsigned int i;

	for (i = 0; i < count; i++) {
		buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL);
		if (!buf) {
688 689
			pr_debug("%s(), kmalloc() failed for %s buffer %u\n",
					__func__, name, i);
690 691 692 693 694 695
			return;
		}
		n_hdlc_buf_put(list, buf);
	}
}

L
Linus Torvalds 已提交
696 697 698 699 700 701 702
/**
 * n_hdlc_alloc - allocate an n_hdlc instance data structure
 *
 * Returns a pointer to newly created structure if success, otherwise %NULL
 */
static struct n_hdlc *n_hdlc_alloc(void)
{
703
	struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);
L
Linus Torvalds 已提交
704 705 706 707

	if (!n_hdlc)
		return NULL;

708 709 710 711
	spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
	spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
	spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
	spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
712 713 714 715 716 717

	INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list);
	INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list);
	INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
	INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);

718 719 720
	n_hdlc_alloc_buf(&n_hdlc->rx_free_buf_list, DEFAULT_RX_BUF_COUNT, "rx");
	n_hdlc_alloc_buf(&n_hdlc->tx_free_buf_list, DEFAULT_TX_BUF_COUNT, "tx");

L
Linus Torvalds 已提交
721 722
	/* Initialize the control block */
	n_hdlc->magic  = HDLC_MAGIC;
J
Jiri Slaby 已提交
723

L
Linus Torvalds 已提交
724
	return n_hdlc;
725

L
Linus Torvalds 已提交
726 727
}	/* end of n_hdlc_alloc() */

728 729
/**
 * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list
J
Jiri Slaby 已提交
730 731
 * @buf_list: pointer to the buffer list
 * @buf: pointer to the buffer
732 733 734 735 736 737 738 739 740 741 742 743 744 745
 */
static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
						struct n_hdlc_buf *buf)
{
	unsigned long flags;

	spin_lock_irqsave(&buf_list->spinlock, flags);

	list_add(&buf->list_item, &buf_list->list);
	buf_list->count++;

	spin_unlock_irqrestore(&buf_list->spinlock, flags);
}

L
Linus Torvalds 已提交
746 747
/**
 * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
J
Jiri Slaby 已提交
748 749
 * @buf_list: pointer to buffer list
 * @buf: pointer to buffer
L
Linus Torvalds 已提交
750
 */
751
static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
L
Linus Torvalds 已提交
752 753 754
			   struct n_hdlc_buf *buf)
{
	unsigned long flags;
755 756 757 758 759 760 761

	spin_lock_irqsave(&buf_list->spinlock, flags);

	list_add_tail(&buf->list_item, &buf_list->list);
	buf_list->count++;

	spin_unlock_irqrestore(&buf_list->spinlock, flags);
L
Linus Torvalds 已提交
762 763 764 765
}	/* end of n_hdlc_buf_put() */

/**
 * n_hdlc_buf_get - remove and return an HDLC buffer from list
J
Jiri Slaby 已提交
766
 * @buf_list: pointer to HDLC buffer list
767
 *
L
Linus Torvalds 已提交
768 769 770 771
 * Remove and return an HDLC buffer from the head of the specified HDLC buffer
 * list.
 * Returns a pointer to HDLC buffer if available, otherwise %NULL.
 */
772
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
L
Linus Torvalds 已提交
773 774 775
{
	unsigned long flags;
	struct n_hdlc_buf *buf;
776 777 778 779 780

	spin_lock_irqsave(&buf_list->spinlock, flags);

	buf = list_first_entry_or_null(&buf_list->list,
						struct n_hdlc_buf, list_item);
L
Linus Torvalds 已提交
781
	if (buf) {
782 783
		list_del(&buf->list_item);
		buf_list->count--;
L
Linus Torvalds 已提交
784
	}
785 786

	spin_unlock_irqrestore(&buf_list->spinlock, flags);
L
Linus Torvalds 已提交
787 788 789
	return buf;
}	/* end of n_hdlc_buf_get() */

790 791
static struct tty_ldisc_ops n_hdlc_ldisc = {
	.owner		= THIS_MODULE,
792
	.num		= N_HDLC,
793 794 795 796 797 798 799 800 801 802 803 804
	.name		= "hdlc",
	.open		= n_hdlc_tty_open,
	.close		= n_hdlc_tty_close,
	.read		= n_hdlc_tty_read,
	.write		= n_hdlc_tty_write,
	.ioctl		= n_hdlc_tty_ioctl,
	.poll		= n_hdlc_tty_poll,
	.receive_buf	= n_hdlc_tty_receive,
	.write_wakeup	= n_hdlc_tty_wakeup,
	.flush_buffer   = flush_rx_queue,
};

L
Linus Torvalds 已提交
805 806 807 808 809
static int __init n_hdlc_init(void)
{
	int status;

	/* range check maxframe arg */
J
Jiri Slaby 已提交
810
	maxframe = clamp(maxframe, 4096, MAX_HDLC_FRAME_SIZE);
L
Linus Torvalds 已提交
811

812
	status = tty_register_ldisc(&n_hdlc_ldisc);
L
Linus Torvalds 已提交
813
	if (!status)
814 815
		pr_info("N_HDLC line discipline registered with maxframe=%d\n",
				maxframe);
L
Linus Torvalds 已提交
816
	else
817 818
		pr_err("N_HDLC: error registering line discipline: %d\n",
				status);
L
Linus Torvalds 已提交
819 820

	return status;
821

L
Linus Torvalds 已提交
822 823 824 825
}	/* end of init_module() */

static void __exit n_hdlc_exit(void)
{
826
	tty_unregister_ldisc(&n_hdlc_ldisc);
L
Linus Torvalds 已提交
827 828 829 830 831 832 833 834 835
}

module_init(n_hdlc_init);
module_exit(n_hdlc_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
module_param(maxframe, int, 0);
MODULE_ALIAS_LDISC(N_HDLC);