File Index
Files and directories
Sign in
FILE

n_hdlc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/tty/n_hdlc.c C
  1// SPDX-License-Identifier: GPL-1.0+
  2/* generic HDLC line discipline for Linux
  3 *
  4 * Written by Paul Fulghum paulkf@microgate.com
  5 * for Microgate Corporation
  6 *
  7 * Microgate and SyncLink are registered trademarks of Microgate Corporation
  8 *
  9 * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
 10 *	Al Longyear <longyear@netcom.com>,
 11 *	Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
 12 *
 13 * Original release 01/11/99
 14 *
 15 * This module implements the tty line discipline N_HDLC for use with
 16 * tty device drivers that support bit-synchronous HDLC communications.
 17 *
 18 * All HDLC data is frame oriented which means:
 19 *
 20 * 1. tty write calls represent one complete transmit frame of data
 21 *    The device driver should accept the complete frame or none of
 22 *    the frame (busy) in the write method. Each write call should have
 23 *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
 24 *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
 25 *    should include any crc bytes required. For example, when using
 26 *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
 27 *    the application may transmit is limited to 65531 bytes. For CCITT
 28 *    CRC16, the maximum application frame size would be 65533.
 29 *
 30 *
 31 * 2. receive callbacks from the device driver represents
 32 *    one received frame. The device driver should bypass
 33 *    the tty flip buffer and call the line discipline receive
 34 *    callback directly to avoid fragmenting or concatenating
 35 *    multiple frames into a single receive callback.
 36 *
 37 *    The HDLC line discipline queues the receive frames in separate
 38 *    buffers so complete receive frames can be returned by the
 39 *    tty read calls.
 40 *
 41 * 3. tty read calls returns an entire frame of data or nothing.
 42 *
 43 * 4. all send and receive data is considered raw. No processing
 44 *    or translation is performed by the line discipline, regardless
 45 *    of the tty flags
 46 *
 47 * 5. When line discipline is queried for the amount of receive
 48 *    data available (FIOC), 0 is returned if no data available,
 49 *    otherwise the count of the next available frame is returned.
 50 *    (instead of the sum of all received frame counts).
 51 *
 52 * These conventions allow the standard tty programming interface
 53 * to be used for synchronous HDLC applications when used with
 54 * this line discipline (or another line discipline that is frame
 55 * oriented such as N_PPP).
 56 *
 57 * The SyncLink driver (synclink.c) implements both asynchronous
 58 * (using standard line discipline N_TTY) and synchronous HDLC
 59 * (using N_HDLC) communications, with the latter using the above
 60 * conventions.
 61 *
 62 * This implementation is very basic and does not maintain
 63 * any statistics. The main point is to enforce the raw data
 64 * and frame orientation of HDLC communications.
 65 *
 66 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 67 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 68 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 69 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 70 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 71 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 72 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 73 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 74 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 75 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 76 * OF THE POSSIBILITY OF SUCH DAMAGE.
 77 */
 78
 79#include <linux/module.h>
 80#include <linux/init.h>
 81#include <linux/kernel.h>
 82#include <linux/sched.h>
 83#include <linux/types.h>
 84#include <linux/fcntl.h>
 85#include <linux/interrupt.h>
 86#include <linux/ptrace.h>
 87
 88#include <linux/poll.h>
 89#include <linux/in.h>
 90#include <linux/ioctl.h>
 91#include <linux/slab.h>
 92#include <linux/tty.h>
 93#include <linux/errno.h>
 94#include <linux/string.h>	/* used in new tty drivers */
 95#include <linux/signal.h>	/* used in new tty drivers */
 96#include <linux/if.h>
 97#include <linux/bitops.h>
 98
 99#include <linux/uaccess.h>
100#include "tty.h"
101
102/*
103 * Buffers for individual HDLC frames
104 */
105#define MAX_HDLC_FRAME_SIZE 65535
106#define DEFAULT_RX_BUF_COUNT 10
107#define MAX_RX_BUF_COUNT 60
108#define DEFAULT_TX_BUF_COUNT 3
109
110struct n_hdlc_buf {
111	struct list_head  list_item;
112	size_t		  count;
113	u8		  buf[];
114};
115
116struct n_hdlc_buf_list {
117	struct list_head  list;
118	int		  count;
119	spinlock_t	  spinlock;
120};
121
122/**
123 * struct n_hdlc - per device instance data structure
124 * @tbusy: reentrancy flag for tx wakeup code
125 * @woke_up: tx wakeup needs to be run again as it was called while @tbusy
126 * @tx_buf_list: list of pending transmit frame buffers
127 * @rx_buf_list: list of received frame buffers
128 * @tx_free_buf_list: list unused transmit frame buffers
129 * @rx_free_buf_list: list unused received frame buffers
130 */
131struct n_hdlc {
132	bool			tbusy;
133	bool			woke_up;
134	struct n_hdlc_buf_list	tx_buf_list;
135	struct n_hdlc_buf_list	rx_buf_list;
136	struct n_hdlc_buf_list	tx_free_buf_list;
137	struct n_hdlc_buf_list	rx_free_buf_list;
138	struct work_struct	write_work;
139	struct tty_struct	*tty_for_write_work;
140};
141
142/*
143 * HDLC buffer list manipulation functions
144 */
145static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
146						struct n_hdlc_buf *buf);
147static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
148			   struct n_hdlc_buf *buf);
149static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
150
151/* Local functions */
152
153static struct n_hdlc *n_hdlc_alloc(void);
154static void n_hdlc_tty_write_work(struct work_struct *work);
155
156/* max frame size for memory allocations */
157static int maxframe = 4096;
158
159static void flush_rx_queue(struct tty_struct *tty)
160{
161	struct n_hdlc *n_hdlc = tty->disc_data;
162	struct n_hdlc_buf *buf;
163
164	while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
165		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
166}
167
168static void flush_tx_queue(struct tty_struct *tty)
169{
170	struct n_hdlc *n_hdlc = tty->disc_data;
171	struct n_hdlc_buf *buf;
172
173	while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
174		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
175}
176
177static void n_hdlc_free_buf_list(struct n_hdlc_buf_list *list)
178{
179	struct n_hdlc_buf *buf;
180
181	do {
182		buf = n_hdlc_buf_get(list);
183		kfree(buf);
184	} while (buf);
185}
186
187/**
188 * n_hdlc_tty_close - line discipline close
189 * @tty: pointer to tty info structure
190 *
191 * Called when the line discipline is changed to something
192 * else, the tty is closed, or the tty detects a hangup.
193 */
194static void n_hdlc_tty_close(struct tty_struct *tty)
195{
196	struct n_hdlc *n_hdlc = tty->disc_data;
197
198#if defined(TTY_NO_WRITE_SPLIT)
199	clear_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
200#endif
201	tty->disc_data = NULL;
202
203	/* Ensure that the n_hdlcd process is not hanging on select()/poll() */
204	wake_up_interruptible(&tty->read_wait);
205	wake_up_interruptible(&tty->write_wait);
206
207	cancel_work_sync(&n_hdlc->write_work);
208
209	n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list);
210	n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list);
211	n_hdlc_free_buf_list(&n_hdlc->rx_buf_list);
212	n_hdlc_free_buf_list(&n_hdlc->tx_buf_list);
213	kfree(n_hdlc);
214}	/* end of n_hdlc_tty_close() */
215
216/**
217 * n_hdlc_tty_open - called when line discipline changed to n_hdlc
218 * @tty: pointer to tty info structure
219 *
220 * Returns 0 if success, otherwise error code
221 */
222static int n_hdlc_tty_open(struct tty_struct *tty)
223{
224	struct n_hdlc *n_hdlc = tty->disc_data;
225
226	pr_debug("%s() called (device=%s)\n", __func__, tty->name);
227
228	/* There should not be an existing table for this slot. */
229	if (n_hdlc) {
230		pr_err("%s: tty already associated!\n", __func__);
231		return -EEXIST;
232	}
233
234	n_hdlc = n_hdlc_alloc();
235	if (!n_hdlc) {
236		pr_err("%s: n_hdlc_alloc failed\n", __func__);
237		return -ENFILE;
238	}
239
240	INIT_WORK(&n_hdlc->write_work, n_hdlc_tty_write_work);
241	n_hdlc->tty_for_write_work = tty;
242	tty->disc_data = n_hdlc;
243	tty->receive_room = 65536;
244
245	/* change tty_io write() to not split large writes into 8K chunks */
246	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
247
248	/* flush receive data from driver */
249	tty_driver_flush_buffer(tty);
250
251	return 0;
252
253}	/* end of n_tty_hdlc_open() */
254
255/**
256 * n_hdlc_send_frames - send frames on pending send buffer list
257 * @n_hdlc: pointer to ldisc instance data
258 * @tty: pointer to tty instance data
259 *
260 * Send frames on pending send buffer list until the driver does not accept a
261 * frame (busy) this function is called after adding a frame to the send buffer
262 * list and by the tty wakeup callback.
263 */
264static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
265{
266	struct n_hdlc_buf *tbuf;
267	ssize_t actual;
268
269check_again:
270	scoped_guard(spinlock_irqsave, &n_hdlc->tx_buf_list.spinlock) {
271		if (n_hdlc->tbusy) {
272			n_hdlc->woke_up = true;
273			return;
274		}
275		n_hdlc->tbusy = true;
276		n_hdlc->woke_up = false;
277	}
278
279	tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
280	while (tbuf) {
281		pr_debug("sending frame %p, count=%zu\n", tbuf, tbuf->count);
282
283		/* Send the next block of data to device */
284		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
285		actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
286
287		/* rollback was possible and has been done */
288		if (actual == -ERESTARTSYS) {
289			n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
290			break;
291		}
292		/* if transmit error, throw frame away by */
293		/* pretending it was accepted by driver */
294		if (actual < 0)
295			actual = tbuf->count;
296
297		if (actual == tbuf->count) {
298			pr_debug("frame %p completed\n", tbuf);
299
300			/* free current transmit buffer */
301			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
302
303			/* wait up sleeping writers */
304			wake_up_interruptible(&tty->write_wait);
305
306			/* get next pending transmit buffer */
307			tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
308		} else {
309			pr_debug("frame %p pending\n", tbuf);
310
311			/*
312			 * the buffer was not accepted by driver,
313			 * return it back into tx queue
314			 */
315			n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
316			break;
317		}
318	}
319
320	if (!tbuf)
321		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
322
323	/* Clear the re-entry flag */
324	scoped_guard(spinlock_irqsave, &n_hdlc->tx_buf_list.spinlock)
325		n_hdlc->tbusy = false;
326
327	if (n_hdlc->woke_up)
328		goto check_again;
329}	/* end of n_hdlc_send_frames() */
330
331/**
332 * n_hdlc_tty_write_work - Asynchronous callback for transmit wakeup
333 * @work: pointer to work_struct
334 *
335 * Called when low level device driver can accept more send data.
336 */
337static void n_hdlc_tty_write_work(struct work_struct *work)
338{
339	struct n_hdlc *n_hdlc = container_of(work, struct n_hdlc, write_work);
340	struct tty_struct *tty = n_hdlc->tty_for_write_work;
341
342	n_hdlc_send_frames(n_hdlc, tty);
343}	/* end of n_hdlc_tty_write_work() */
344
345/**
346 * n_hdlc_tty_wakeup - Callback for transmit wakeup
347 * @tty: pointer to associated tty instance data
348 *
349 * Called when low level device driver can accept more send data.
350 */
351static void n_hdlc_tty_wakeup(struct tty_struct *tty)
352{
353	struct n_hdlc *n_hdlc = tty->disc_data;
354
355	schedule_work(&n_hdlc->write_work);
356}	/* end of n_hdlc_tty_wakeup() */
357
358/**
359 * n_hdlc_tty_receive - Called by tty driver when receive data is available
360 * @tty: pointer to tty instance data
361 * @data: pointer to received data
362 * @flags: pointer to flags for data
363 * @count: count of received data in bytes
364 *
365 * Called by tty low level driver when receive data is available. Data is
366 * interpreted as one HDLC frame.
367 */
368static void n_hdlc_tty_receive(struct tty_struct *tty, const u8 *data,
369			       const u8 *flags, size_t count)
370{
371	register struct n_hdlc *n_hdlc = tty->disc_data;
372	register struct n_hdlc_buf *buf;
373
374	pr_debug("%s() called count=%zu\n", __func__, count);
375
376	if (count > maxframe) {
377		pr_debug("rx count>maxframesize, data discarded\n");
378		return;
379	}
380
381	/* get a free HDLC buffer */
382	buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
383	if (!buf) {
384		/*
385		 * no buffers in free list, attempt to allocate another rx
386		 * buffer unless the maximum count has been reached
387		 */
388		if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
389			buf = kmalloc(struct_size(buf, buf, maxframe),
390				      GFP_ATOMIC);
391	}
392
393	if (!buf) {
394		pr_debug("no more rx buffers, data discarded\n");
395		return;
396	}
397
398	/* copy received data to HDLC buffer */
399	memcpy(buf->buf, data, count);
400	buf->count = count;
401
402	/* add HDLC buffer to list of received frames */
403	n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
404
405	/* wake up any blocked reads and perform async signalling */
406	wake_up_interruptible(&tty->read_wait);
407	if (tty->fasync != NULL)
408		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
409
410}	/* end of n_hdlc_tty_receive() */
411
412/**
413 * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
414 * @tty: pointer to tty instance data
415 * @file: pointer to open file object
416 * @kbuf: pointer to returned data buffer
417 * @nr: size of returned data buffer
418 * @cookie: stored rbuf from previous run
419 * @offset: offset into the data buffer
420 *
421 * Returns the number of bytes returned or error code.
422 */
423static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
424			       u8 *kbuf, size_t nr, void **cookie,
425			       unsigned long offset)
426{
427	struct n_hdlc *n_hdlc = tty->disc_data;
428	int ret = 0;
429	struct n_hdlc_buf *rbuf;
430	DECLARE_WAITQUEUE(wait, current);
431
432	/* Is this a repeated call for an rbuf we already found earlier? */
433	rbuf = *cookie;
434	if (rbuf)
435		goto have_rbuf;
436
437	add_wait_queue(&tty->read_wait, &wait);
438
439	for (;;) {
440		if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
441			ret = -EIO;
442			break;
443		}
444		if (tty_hung_up_p(file))
445			break;
446
447		set_current_state(TASK_INTERRUPTIBLE);
448
449		rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
450		if (rbuf)
451			break;
452
453		/* no data */
454		if (tty_io_nonblock(tty, file)) {
455			ret = -EAGAIN;
456			break;
457		}
458
459		schedule();
460
461		if (signal_pending(current)) {
462			ret = -EINTR;
463			break;
464		}
465	}
466
467	remove_wait_queue(&tty->read_wait, &wait);
468	__set_current_state(TASK_RUNNING);
469
470	if (!rbuf)
471		return ret;
472	*cookie = rbuf;
473
474have_rbuf:
475	/* Have we used it up entirely? */
476	if (offset >= rbuf->count)
477		goto done_with_rbuf;
478
479	/* More data to go, but can't copy any more? EOVERFLOW */
480	ret = -EOVERFLOW;
481	if (!nr)
482		goto done_with_rbuf;
483
484	/* Copy as much data as possible */
485	ret = rbuf->count - offset;
486	if (ret > nr)
487		ret = nr;
488	memcpy(kbuf, rbuf->buf+offset, ret);
489	offset += ret;
490
491	/* If we still have data left, we leave the rbuf in the cookie */
492	if (offset < rbuf->count)
493		return ret;
494
495done_with_rbuf:
496	*cookie = NULL;
497
498	if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
499		kfree(rbuf);
500	else
501		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf);
502
503	return ret;
504
505}	/* end of n_hdlc_tty_read() */
506
507/**
508 * n_hdlc_tty_write - write a single frame of data to device
509 * @tty: pointer to associated tty device instance data
510 * @file: pointer to file object data
511 * @data: pointer to transmit data (one frame)
512 * @count: size of transmit frame in bytes
513 *
514 * Returns the number of bytes written (or error code).
515 */
516static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
517				const u8 *data, size_t count)
518{
519	struct n_hdlc *n_hdlc = tty->disc_data;
520	DECLARE_WAITQUEUE(wait, current);
521	struct n_hdlc_buf *tbuf;
522	ssize_t error = 0;
523
524	pr_debug("%s() called count=%zd\n", __func__, count);
525
526	/* verify frame size */
527	if (count > maxframe) {
528		pr_debug("%s: truncating user packet from %zu to %d\n",
529				__func__, count, maxframe);
530		count = maxframe;
531	}
532
533	add_wait_queue(&tty->write_wait, &wait);
534
535	for (;;) {
536		set_current_state(TASK_INTERRUPTIBLE);
537
538		tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
539		if (tbuf)
540			break;
541
542		if (tty_io_nonblock(tty, file)) {
543			error = -EAGAIN;
544			break;
545		}
546		schedule();
547
548		if (signal_pending(current)) {
549			error = -EINTR;
550			break;
551		}
552	}
553
554	__set_current_state(TASK_RUNNING);
555	remove_wait_queue(&tty->write_wait, &wait);
556
557	if (!error) {
558		/* Retrieve the user's buffer */
559		memcpy(tbuf->buf, data, count);
560
561		/* Send the data */
562		tbuf->count = error = count;
563		n_hdlc_buf_put(&n_hdlc->tx_buf_list, tbuf);
564		n_hdlc_send_frames(n_hdlc, tty);
565	}
566
567	return error;
568
569}	/* end of n_hdlc_tty_write() */
570
571/**
572 * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
573 * @tty: pointer to tty instance data
574 * @cmd: IOCTL command code
575 * @arg: argument for IOCTL call (cmd dependent)
576 *
577 * Returns command dependent result.
578 */
579static int n_hdlc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
580			    unsigned long arg)
581{
582	struct n_hdlc *n_hdlc = tty->disc_data;
583	int count;
584	struct n_hdlc_buf *buf = NULL;
585
586	pr_debug("%s() called %d\n", __func__, cmd);
587
588	switch (cmd) {
589	case FIONREAD:
590		/* report count of read data available */
591		/* in next available frame (if any) */
592		scoped_guard(spinlock_irqsave, &n_hdlc->rx_buf_list.spinlock) {
593			buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
594						       struct n_hdlc_buf, list_item);
595			if (buf)
596				count = buf->count;
597			else
598				count = 0;
599		}
600		return put_user(count, (int __user *)arg);
601
602	case TIOCOUTQ:
603		/* get the pending tx byte count in the driver */
604		count = tty_chars_in_buffer(tty);
605		/* add size of next output frame in queue */
606		scoped_guard(spinlock_irqsave, &n_hdlc->tx_buf_list.spinlock) {
607			buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
608						       struct n_hdlc_buf, list_item);
609			if (buf)
610				count += buf->count;
611		}
612		return put_user(count, (int __user *)arg);
613
614	case TCFLSH:
615		switch (arg) {
616		case TCIOFLUSH:
617		case TCOFLUSH:
618			flush_tx_queue(tty);
619		}
620		fallthrough;	/* to default */
621
622	default:
623		return n_tty_ioctl_helper(tty, cmd, arg);
624	}
625}	/* end of n_hdlc_tty_ioctl() */
626
627/**
628 * n_hdlc_tty_poll - TTY callback for poll system call
629 * @tty: pointer to tty instance data
630 * @filp: pointer to open file object for device
631 * @wait: wait queue for operations
632 *
633 * Determine which operations (read/write) will not block and return info
634 * to caller.
635 * Returns a bit mask containing info on which ops will not block.
636 */
637static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
638				    poll_table *wait)
639{
640	struct n_hdlc *n_hdlc = tty->disc_data;
641	__poll_t mask = 0;
642
643	/*
644	 * queue the current process into any wait queue that may awaken in the
645	 * future (read and write)
646	 */
647	poll_wait(filp, &tty->read_wait, wait);
648	poll_wait(filp, &tty->write_wait, wait);
649
650	/* set bits for operations that won't block */
651	if (!list_empty(&n_hdlc->rx_buf_list.list))
652		mask |= EPOLLIN | EPOLLRDNORM;	/* readable */
653	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
654		mask |= EPOLLHUP;
655	if (tty_hung_up_p(filp))
656		mask |= EPOLLHUP;
657	if (!tty_is_writelocked(tty) &&
658			!list_empty(&n_hdlc->tx_free_buf_list.list))
659		mask |= EPOLLOUT | EPOLLWRNORM;	/* writable */
660
661	return mask;
662}	/* end of n_hdlc_tty_poll() */
663
664static void n_hdlc_alloc_buf(struct n_hdlc_buf_list *list, unsigned int count,
665		const char *name)
666{
667	struct n_hdlc_buf *buf;
668	unsigned int i;
669
670	for (i = 0; i < count; i++) {
671		buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL);
672		if (!buf) {
673			pr_debug("%s(), kmalloc() failed for %s buffer %u\n",
674					__func__, name, i);
675			return;
676		}
677		n_hdlc_buf_put(list, buf);
678	}
679}
680
681/**
682 * n_hdlc_alloc - allocate an n_hdlc instance data structure
683 *
684 * Returns a pointer to newly created structure if success, otherwise %NULL
685 */
686static struct n_hdlc *n_hdlc_alloc(void)
687{
688	struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);
689
690	if (!n_hdlc)
691		return NULL;
692
693	spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
694	spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
695	spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
696	spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
697
698	INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list);
699	INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list);
700	INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
701	INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);
702
703	n_hdlc_alloc_buf(&n_hdlc->rx_free_buf_list, DEFAULT_RX_BUF_COUNT, "rx");
704	n_hdlc_alloc_buf(&n_hdlc->tx_free_buf_list, DEFAULT_TX_BUF_COUNT, "tx");
705
706	return n_hdlc;
707
708}	/* end of n_hdlc_alloc() */
709
710/**
711 * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list
712 * @buf_list: pointer to the buffer list
713 * @buf: pointer to the buffer
714 */
715static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
716						struct n_hdlc_buf *buf)
717{
718	guard(spinlock_irqsave)(&buf_list->spinlock);
719
720	list_add(&buf->list_item, &buf_list->list);
721	buf_list->count++;
722}
723
724/**
725 * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
726 * @buf_list: pointer to buffer list
727 * @buf: pointer to buffer
728 */
729static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
730			   struct n_hdlc_buf *buf)
731{
732	guard(spinlock_irqsave)(&buf_list->spinlock);
733
734	list_add_tail(&buf->list_item, &buf_list->list);
735	buf_list->count++;
736}	/* end of n_hdlc_buf_put() */
737
738/**
739 * n_hdlc_buf_get - remove and return an HDLC buffer from list
740 * @buf_list: pointer to HDLC buffer list
741 *
742 * Remove and return an HDLC buffer from the head of the specified HDLC buffer
743 * list.
744 * Returns a pointer to HDLC buffer if available, otherwise %NULL.
745 */
746static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
747{
748	struct n_hdlc_buf *buf;
749
750	guard(spinlock_irqsave)(&buf_list->spinlock);
751
752	buf = list_first_entry_or_null(&buf_list->list,
753						struct n_hdlc_buf, list_item);
754	if (buf) {
755		list_del(&buf->list_item);
756		buf_list->count--;
757	}
758
759	return buf;
760}	/* end of n_hdlc_buf_get() */
761
762static struct tty_ldisc_ops n_hdlc_ldisc = {
763	.owner		= THIS_MODULE,
764	.num		= N_HDLC,
765	.name		= "hdlc",
766	.open		= n_hdlc_tty_open,
767	.close		= n_hdlc_tty_close,
768	.read		= n_hdlc_tty_read,
769	.write		= n_hdlc_tty_write,
770	.ioctl		= n_hdlc_tty_ioctl,
771	.poll		= n_hdlc_tty_poll,
772	.receive_buf	= n_hdlc_tty_receive,
773	.write_wakeup	= n_hdlc_tty_wakeup,
774	.flush_buffer   = flush_rx_queue,
775};
776
777static int __init n_hdlc_init(void)
778{
779	int status;
780
781	/* range check maxframe arg */
782	maxframe = clamp(maxframe, 4096, MAX_HDLC_FRAME_SIZE);
783
784	status = tty_register_ldisc(&n_hdlc_ldisc);
785	if (!status)
786		pr_info("N_HDLC line discipline registered with maxframe=%d\n",
787				maxframe);
788	else
789		pr_err("N_HDLC: error registering line discipline: %d\n",
790				status);
791
792	return status;
793
794}	/* end of init_module() */
795
796static void __exit n_hdlc_exit(void)
797{
798	tty_unregister_ldisc(&n_hdlc_ldisc);
799}
800
801module_init(n_hdlc_init);
802module_exit(n_hdlc_exit);
803
804MODULE_DESCRIPTION("HDLC line discipline support");
805MODULE_LICENSE("GPL");
806MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
807module_param(maxframe, int, 0);
808MODULE_ALIAS_LDISC(N_HDLC);
~/ Read-only file preview.