linux/drivers/tty/n_gsm.c

// SPDX-License-Identifier: GPL-2.0
/*
 * n_gsm.c GSM 0710 tty multiplexor
 * Copyright (c) 2009/10 Intel Corporation
 * Copyright (c) 2022/23 Siemens Mobility GmbH
 *
 *	* THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE *
 *
 * Outgoing path:
 * tty -> DLCI fifo -> scheduler -> GSM MUX data queue    ---o-> ldisc
 * control message               -> GSM MUX control queue --´
 *
 * Incoming path:
 * ldisc -> gsm_queue() -o--> tty
 *                        `-> gsm_control_response()
 *
 * TO DO:
 *	Mostly done:	ioctls for setting modes/timing
 *	Partly done:	hooks so you can pull off frames to non tty devs
 *	Restart DLCI 0 when it closes ?
 *	Improve the tx engine
 *	Resolve tx side locking by adding a queue_head and routing
 *		all control traffic via it
 *	General tidy/document
 *	Review the locking/move to refcounts more (mux now moved to an
 *		alloc/free model ready)
 *	Use newest tty open/close port helpers and install hooks
 *	What to do about power functions ?
 *	Termios setting and negotiation
 *	Do we need a 'which mux are you' ioctl to correlate mux and tty sets
 *
 */

#include <linux/types.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/fcntl.h>
#include <linux/sched/signal.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/bitfield.h>
#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/math.h>
#include <linux/nospec.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/bitops.h>
#include <linux/file.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/tty_flip.h>
#include <linux/tty_driver.h>
#include <linux/serial.h>
#include <linux/kfifo.h>
#include <linux/skbuff.h>
#include <net/arp.h>
#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/gsmmux.h>
#include "tty.h"

static int debug;
module_param(debug, int, 0600);

/* Module debug bits */
#define DBG_DUMP
#define DBG_CD_ON
#define DBG_DATA
#define DBG_ERRORS
#define DBG_TTY
#define DBG_PAYLOAD

/* Defaults: these are from the specification */

#define T1
#define T2
#define T3
#define N2
#define K

#define MAX_T3
#define MAX_WINDOW_SIZE

/* Use long timers for testing at low speed with debug on */
#ifdef DEBUG_TIMING
#define T1
#define T2
#endif

/*
 * Semi-arbitrary buffer size limits. 0710 is normally run with 32-64 byte
 * limits so this is plenty
 */
#define MAX_MRU
#define MAX_MTU
#define MIN_MTU
/* SOF, ADDR, CTRL, LEN1, LEN2, ..., FCS, EOF */
#define PROT_OVERHEAD
#define GSM_NET_TX_TIMEOUT

/*
 *	struct gsm_mux_net	-	network interface
 *
 *	Created when net interface is initialized.
 */
struct gsm_mux_net {};

/*
 *	Each block of data we have queued to go out is in the form of
 *	a gsm_msg which holds everything we need in a link layer independent
 *	format
 */

struct gsm_msg {};

enum gsm_dlci_state {};

enum gsm_dlci_mode {};

/*
 *	Each active data link has a gsm_dlci structure associated which ties
 *	the link layer to an optional tty (if the tty side is open). To avoid
 *	complexity right now these are only ever freed up when the mux is
 *	shut down.
 *
 *	At the moment we don't free DLCI objects until the mux is torn down
 *	this avoid object life time issues but might be worth review later.
 */

struct gsm_dlci {};

/*
 * Parameter bits used for parameter negotiation according to 3GPP 27.010
 * chapter 5.4.6.3.1.
 */

struct gsm_dlci_param_bits {};

static_assert();

#define PN_D_FIELD_DLCI
#define PN_I_CL_FIELD_FTYPE
#define PN_I_CL_FIELD_ADAPTION
#define PN_P_FIELD_PRIO
#define PN_T_FIELD_T1
#define PN_N_FIELD_N1
#define PN_NA_FIELD_N2
#define PN_K_FIELD_K

/* Total number of supported devices */
#define GSM_TTY_MINORS

/* DLCI 0, 62/63 are special or reserved see gsmtty_open */

#define NUM_DLCI

/*
 *	DLCI 0 is used to pass control blocks out of band of the data
 *	flow (and with a higher link priority). One command can be outstanding
 *	at a time and we use this structure to manage them. They are created
 *	and destroyed by the user context, and updated by the receive paths
 *	and timers
 */

struct gsm_control {};

enum gsm_encoding {};

enum gsm_mux_state {};

/*
 *	Each GSM mux we have is represented by this structure. If we are
 *	operating as an ldisc then we use this structure as our ldisc
 *	state. We need to sort out lifetimes and locking with respect
 *	to the gsm mux array. For now we don't free DLCI objects that
 *	have been instantiated until the mux itself is terminated.
 *
 *	To consider further: tty open versus mux shutdown.
 */

struct gsm_mux {};


/*
 *	Mux objects - needed so that we can translate a tty index into the
 *	relevant mux and DLCI.
 */

#define MAX_MUX
static struct gsm_mux *gsm_mux[MAX_MUX];	/* GSM muxes */
static DEFINE_SPINLOCK(gsm_mux_lock);

static struct tty_driver *gsm_tty_driver;

/*
 *	This section of the driver logic implements the GSM encodings
 *	both the basic and the 'advanced'. Reliable transport is not
 *	supported.
 */

#define CR
#define EA
#define PF

/* I is special: the rest are ..*/
#define RR
#define UI
#define RNR
#define REJ
#define DM
#define SABM
#define DISC
#define UA
#define UIH

/* Channel commands */
#define CMD_NSC
#define CMD_TEST
#define CMD_PSC
#define CMD_RLS
#define CMD_FCOFF
#define CMD_PN
#define CMD_RPN
#define CMD_FCON
#define CMD_CLD
#define CMD_SNC
#define CMD_MSC

/* Virtual modem bits */
#define MDM_FC
#define MDM_RTC
#define MDM_RTR
#define MDM_IC
#define MDM_DV

#define GSM0_SOF
#define GSM1_SOF
#define GSM1_ESCAPE
#define GSM1_ESCAPE_BITS
#define XON
#define XOFF
#define ISO_IEC_646_MASK

static const struct tty_port_operations gsm_port_ops;

/*
 *	CRC table for GSM 0710
 */

static const u8 gsm_fcs8[256] =;

#define INIT_FCS
#define GOOD_FCS

static void gsm_dlci_close(struct gsm_dlci *dlci);
static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
								u8 ctrl);
static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg);
static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr);
static void gsmld_write_trigger(struct gsm_mux *gsm);
static void gsmld_write_task(struct work_struct *work);

/**
 *	gsm_fcs_add	-	update FCS
 *	@fcs: Current FCS
 *	@c: Next data
 *
 *	Update the FCS to include c. Uses the algorithm in the specification
 *	notes.
 */

static inline u8 gsm_fcs_add(u8 fcs, u8 c)
{}

/**
 *	gsm_fcs_add_block	-	update FCS for a block
 *	@fcs: Current FCS
 *	@c: buffer of data
 *	@len: length of buffer
 *
 *	Update the FCS to include c. Uses the algorithm in the specification
 *	notes.
 */

static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len)
{}

/**
 *	gsm_read_ea		-	read a byte into an EA
 *	@val: variable holding value
 *	@c: byte going into the EA
 *
 *	Processes one byte of an EA. Updates the passed variable
 *	and returns 1 if the EA is now completely read
 */

static int gsm_read_ea(unsigned int *val, u8 c)
{}

/**
 *	gsm_read_ea_val	-	read a value until EA
 *	@val: variable holding value
 *	@data: buffer of data
 *	@dlen: length of data
 *
 *	Processes an EA value. Updates the passed variable and
 *	returns the processed data length.
 */
static unsigned int gsm_read_ea_val(unsigned int *val, const u8 *data, int dlen)
{}

/**
 *	gsm_encode_modem	-	encode modem data bits
 *	@dlci: DLCI to encode from
 *
 *	Returns the correct GSM encoded modem status bits (6 bit field) for
 *	the current status of the DLCI and attached tty object
 */

static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
{}

static void gsm_hex_dump_bytes(const char *fname, const u8 *data,
			       unsigned long len)
{}

/**
 * gsm_encode_params	-	encode DLCI parameters
 * @dlci: DLCI to encode from
 * @params: buffer to fill with the encoded parameters
 *
 * Encodes the parameters according to GSM 07.10 section 5.4.6.3.1
 * table 3.
 */
static int gsm_encode_params(const struct gsm_dlci *dlci,
			     struct gsm_dlci_param_bits *params)
{}

/**
 *	gsm_register_devices	-	register all tty devices for a given mux index
 *
 *	@driver: the tty driver that describes the tty devices
 *	@index:  the mux number is used to calculate the minor numbers of the
 *	         ttys for this mux and may differ from the position in the
 *	         mux array.
 */
static int gsm_register_devices(struct tty_driver *driver, unsigned int index)
{}

/**
 *	gsm_unregister_devices	-	unregister all tty devices for a given mux index
 *
 *	@driver: the tty driver that describes the tty devices
 *	@index:  the mux number is used to calculate the minor numbers of the
 *	         ttys for this mux and may differ from the position in the
 *	         mux array.
 */
static void gsm_unregister_devices(struct tty_driver *driver,
				   unsigned int index)
{}

/**
 *	gsm_print_packet	-	display a frame for debug
 *	@hdr: header to print before decode
 *	@addr: address EA from the frame
 *	@cr: C/R bit seen as initiator
 *	@control: control including PF bit
 *	@data: following data bytes
 *	@dlen: length of data
 *
 *	Displays a packet in human readable format for debugging purposes. The
 *	style is based on amateur radio LAP-B dump display.
 */

static void gsm_print_packet(const char *hdr, int addr, int cr,
					u8 control, const u8 *data, int dlen)
{}


/*
 *	Link level transmission side
 */

/**
 *	gsm_stuff_frame	-	bytestuff a packet
 *	@input: input buffer
 *	@output: output buffer
 *	@len: length of input
 *
 *	Expand a buffer by bytestuffing it. The worst case size change
 *	is doubling and the caller is responsible for handing out
 *	suitable sized buffers.
 */

static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
{}

/**
 *	gsm_send	-	send a control frame
 *	@gsm: our GSM mux
 *	@addr: address for control frame
 *	@cr: command/response bit seen as initiator
 *	@control:  control byte including PF bit
 *
 *	Format up and transmit a control frame. These should be transmitted
 *	ahead of data when they are needed.
 */
static int gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
{}

/**
 *	gsm_dlci_clear_queues	-	remove outstanding data for a DLCI
 *	@gsm: mux
 *	@dlci: clear for this DLCI
 *
 *	Clears the data queues for a given DLCI.
 */
static void gsm_dlci_clear_queues(struct gsm_mux *gsm, struct gsm_dlci *dlci)
{}

/**
 *	gsm_response	-	send a control response
 *	@gsm: our GSM mux
 *	@addr: address for control frame
 *	@control:  control byte including PF bit
 *
 *	Format up and transmit a link level response frame.
 */

static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
{}

/**
 *	gsm_command	-	send a control command
 *	@gsm: our GSM mux
 *	@addr: address for control frame
 *	@control:  control byte including PF bit
 *
 *	Format up and transmit a link level command frame.
 */

static inline void gsm_command(struct gsm_mux *gsm, int addr, int control)
{}

/* Data transmission */

#define HDR_LEN

/**
 *	gsm_data_alloc		-	allocate data frame
 *	@gsm: GSM mux
 *	@addr: DLCI address
 *	@len: length excluding header and FCS
 *	@ctrl: control byte
 *
 *	Allocate a new data buffer for sending frames with data. Space is left
 *	at the front for header bytes but that is treated as an implementation
 *	detail and not for the high level code to use
 */

static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
								u8 ctrl)
{}

/**
 *	gsm_send_packet	-	sends a single packet
 *	@gsm: GSM Mux
 *	@msg: packet to send
 *
 *	The given packet is encoded and sent out. No memory is freed.
 *	The caller must hold the gsm tx lock.
 */
static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg)
{}

/**
 *	gsm_is_flow_ctrl_msg	-	checks if flow control message
 *	@msg: message to check
 *
 *	Returns true if the given message is a flow control command of the
 *	control channel. False is returned in any other case.
 */
static bool gsm_is_flow_ctrl_msg(struct gsm_msg *msg)
{}

/**
 *	gsm_data_kick	-	poke the queue
 *	@gsm: GSM Mux
 *
 *	The tty device has called us to indicate that room has appeared in
 *	the transmit queue. Ram more data into the pipe if we have any.
 *	If we have been flow-stopped by a CMD_FCOFF, then we can only
 *	send messages on DLCI0 until CMD_FCON. The caller must hold
 *	the gsm tx lock.
 */
static int gsm_data_kick(struct gsm_mux *gsm)
{}

/**
 *	__gsm_data_queue		-	queue a UI or UIH frame
 *	@dlci: DLCI sending the data
 *	@msg: message queued
 *
 *	Add data to the transmit queue and try and get stuff moving
 *	out of the mux tty if not already doing so. The Caller must hold
 *	the gsm tx lock.
 */

static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
{}

/**
 *	gsm_data_queue		-	queue a UI or UIH frame
 *	@dlci: DLCI sending the data
 *	@msg: message queued
 *
 *	Add data to the transmit queue and try and get stuff moving
 *	out of the mux tty if not already doing so. Take the
 *	the gsm tx lock and dlci lock.
 */

static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
{}

/**
 *	gsm_dlci_data_output	-	try and push data out of a DLCI
 *	@gsm: mux
 *	@dlci: the DLCI to pull data from
 *
 *	Pull data from a DLCI and send it into the transmit queue if there
 *	is data. Keep to the MRU of the mux. This path handles the usual tty
 *	interface which is a byte stream with optional modem data.
 *
 *	Caller must hold the tx_lock of the mux.
 */

static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
{}

/**
 *	gsm_dlci_data_output_framed  -	try and push data out of a DLCI
 *	@gsm: mux
 *	@dlci: the DLCI to pull data from
 *
 *	Pull data from a DLCI and send it into the transmit queue if there
 *	is data. Keep to the MRU of the mux. This path handles framed data
 *	queued as skbuffs to the DLCI.
 *
 *	Caller must hold the tx_lock of the mux.
 */

static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
						struct gsm_dlci *dlci)
{}

/**
 *	gsm_dlci_modem_output	-	try and push modem status out of a DLCI
 *	@gsm: mux
 *	@dlci: the DLCI to pull modem status from
 *	@brk: break signal
 *
 *	Push an empty frame in to the transmit queue to update the modem status
 *	bits and to transmit an optional break.
 *
 *	Caller must hold the tx_lock of the mux.
 */

static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
				 u8 brk)
{}

/**
 *	gsm_dlci_data_sweep		-	look for data to send
 *	@gsm: the GSM mux
 *
 *	Sweep the GSM mux channels in priority order looking for ones with
 *	data to send. We could do with optimising this scan a bit. We aim
 *	to fill the queue totally or up to TX_THRESH_HI bytes. Once we hit
 *	TX_THRESH_LO we get called again
 *
 *	FIXME: We should round robin between groups and in theory you can
 *	renegotiate DLCI priorities with optional stuff. Needs optimising.
 */

static int gsm_dlci_data_sweep(struct gsm_mux *gsm)
{}

/**
 *	gsm_dlci_data_kick	-	transmit if possible
 *	@dlci: DLCI to kick
 *
 *	Transmit data from this DLCI if the queue is empty. We can't rely on
 *	a tty wakeup except when we filled the pipe so we need to fire off
 *	new data ourselves in other cases.
 */

static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
{}

/*
 *	Control message processing
 */


/**
 * gsm_control_command	-	send a command frame to a control
 * @gsm: gsm channel
 * @cmd: the command to use
 * @data: data to follow encoded info
 * @dlen: length of data
 *
 * Encode up and queue a UI/UIH frame containing our command.
 */
static int gsm_control_command(struct gsm_mux *gsm, int cmd, const u8 *data,
			       int dlen)
{}

/**
 *	gsm_control_reply	-	send a response frame to a control
 *	@gsm: gsm channel
 *	@cmd: the command to use
 *	@data: data to follow encoded info
 *	@dlen: length of data
 *
 *	Encode up and queue a UI/UIH frame containing our response.
 */

static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
					int dlen)
{}

/**
 *	gsm_process_modem	-	process received modem status
 *	@tty: virtual tty bound to the DLCI
 *	@dlci: DLCI to affect
 *	@modem: modem bits (full EA)
 *	@slen: number of signal octets
 *
 *	Used when a modem control message or line state inline in adaption
 *	layer 2 is processed. Sort out the local modem state and throttles
 */

static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
							u32 modem, int slen)
{}

/**
 * gsm_process_negotiation	-	process received parameters
 * @gsm: GSM channel
 * @addr: DLCI address
 * @cr: command/response
 * @params: encoded parameters from the parameter negotiation message
 *
 * Used when the response for our parameter negotiation command was
 * received.
 */
static int gsm_process_negotiation(struct gsm_mux *gsm, unsigned int addr,
				   unsigned int cr,
				   const struct gsm_dlci_param_bits *params)
{}

/**
 *	gsm_control_modem	-	modem status received
 *	@gsm: GSM channel
 *	@data: data following command
 *	@clen: command length
 *
 *	We have received a modem status control message. This is used by
 *	the GSM mux protocol to pass virtual modem line status and optionally
 *	to indicate break signals. Unpack it, convert to Linux representation
 *	and if need be stuff a break message down the tty.
 */

static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
{}

/**
 * gsm_control_negotiation	-	parameter negotiation received
 * @gsm: GSM channel
 * @cr: command/response flag
 * @data: data following command
 * @dlen: data length
 *
 * We have received a parameter negotiation message. This is used by
 * the GSM mux protocol to configure protocol parameters for a new DLCI.
 */
static void gsm_control_negotiation(struct gsm_mux *gsm, unsigned int cr,
				    const u8 *data, unsigned int dlen)
{}

/**
 *	gsm_control_rls		-	remote line status
 *	@gsm: GSM channel
 *	@data: data bytes
 *	@clen: data length
 *
 *	The modem sends us a two byte message on the control channel whenever
 *	it wishes to send us an error state from the virtual link. Stuff
 *	this into the uplink tty if present
 */

static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen)
{}

static void gsm_dlci_begin_close(struct gsm_dlci *dlci);

/**
 *	gsm_control_message	-	DLCI 0 control processing
 *	@gsm: our GSM mux
 *	@command:  the command EA
 *	@data: data beyond the command/length EAs
 *	@clen: length
 *
 *	Input processor for control messages from the other end of the link.
 *	Processes the incoming request and queues a response frame or an
 *	NSC response if not supported
 */

static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
						const u8 *data, int clen)
{}

/**
 *	gsm_control_response	-	process a response to our control
 *	@gsm: our GSM mux
 *	@command: the command (response) EA
 *	@data: data beyond the command/length EA
 *	@clen: length
 *
 *	Process a response to an outstanding command. We only allow a single
 *	control message in flight so this is fairly easy. All the clean up
 *	is done by the caller, we just update the fields, flag it as done
 *	and return
 */

static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
						const u8 *data, int clen)
{}

/**
 * gsm_control_keep_alive	-	check timeout or start keep-alive
 * @t: timer contained in our gsm object
 *
 * Called off the keep-alive timer expiry signaling that our link
 * partner is not responding anymore. Link will be closed.
 * This is also called to startup our timer.
 */

static void gsm_control_keep_alive(struct timer_list *t)
{}

/**
 *	gsm_control_transmit	-	send control packet
 *	@gsm: gsm mux
 *	@ctrl: frame to send
 *
 *	Send out a pending control command (called under control lock)
 */

static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
{}

/**
 *	gsm_control_retransmit	-	retransmit a control frame
 *	@t: timer contained in our gsm object
 *
 *	Called off the T2 timer expiry in order to retransmit control frames
 *	that have been lost in the system somewhere. The control_lock protects
 *	us from colliding with another sender or a receive completion event.
 *	In that situation the timer may still occur in a small window but
 *	gsm->pending_cmd will be NULL and we just let the timer expire.
 */

static void gsm_control_retransmit(struct timer_list *t)
{}

/**
 *	gsm_control_send	-	send a control frame on DLCI 0
 *	@gsm: the GSM channel
 *	@command: command  to send including CR bit
 *	@data: bytes of data (must be kmalloced)
 *	@clen: length of the block to send
 *
 *	Queue and dispatch a control command. Only one command can be
 *	active at a time. In theory more can be outstanding but the matching
 *	gets really complicated so for now stick to one outstanding.
 */

static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
		unsigned int command, u8 *data, int clen)
{}

/**
 *	gsm_control_wait	-	wait for a control to finish
 *	@gsm: GSM mux
 *	@control: control we are waiting on
 *
 *	Waits for the control to complete or time out. Frees any used
 *	resources and returns 0 for success, or an error if the remote
 *	rejected or ignored the request.
 */

static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
{}


/*
 *	DLCI level handling: Needs krefs
 */

/*
 *	State transitions and timers
 */

/**
 *	gsm_dlci_close		-	a DLCI has closed
 *	@dlci: DLCI that closed
 *
 *	Perform processing when moving a DLCI into closed state. If there
 *	is an attached tty this is hung up
 */

static void gsm_dlci_close(struct gsm_dlci *dlci)
{}

/**
 *	gsm_dlci_open		-	a DLCI has opened
 *	@dlci: DLCI that opened
 *
 *	Perform processing when moving a DLCI into open state.
 */

static void gsm_dlci_open(struct gsm_dlci *dlci)
{}

/**
 * gsm_dlci_negotiate	-	start parameter negotiation
 * @dlci: DLCI to open
 *
 * Starts the parameter negotiation for the new DLCI. This needs to be done
 * before the DLCI initialized the channel via SABM.
 */
static int gsm_dlci_negotiate(struct gsm_dlci *dlci)
{}

/**
 *	gsm_dlci_t1		-	T1 timer expiry
 *	@t: timer contained in the DLCI that opened
 *
 *	The T1 timer handles retransmits of control frames (essentially of
 *	SABM and DISC). We resend the command until the retry count runs out
 *	in which case an opening port goes back to closed and a closing port
 *	is simply put into closed state (any further frames from the other
 *	end will get a DM response)
 *
 *	Some control dlci can stay in ADM mode with other dlci working just
 *	fine. In that case we can just keep the control dlci open after the
 *	DLCI_OPENING retries time out.
 */

static void gsm_dlci_t1(struct timer_list *t)
{}

/**
 *	gsm_dlci_begin_open	-	start channel open procedure
 *	@dlci: DLCI to open
 *
 *	Commence opening a DLCI from the Linux side. We issue SABM messages
 *	to the modem which should then reply with a UA or ADM, at which point
 *	we will move into open state. Opening is done asynchronously with retry
 *	running off timers and the responses.
 *	Parameter negotiation is performed before SABM if required.
 */

static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
{}

/**
 *	gsm_dlci_set_opening	-	change state to opening
 *	@dlci: DLCI to open
 *
 *	Change internal state to wait for DLCI open from initiator side.
 *	We set off timers and responses upon reception of an SABM.
 */
static void gsm_dlci_set_opening(struct gsm_dlci *dlci)
{}

/**
 * gsm_dlci_set_wait_config	-	wait for channel configuration
 * @dlci: DLCI to configure
 *
 * Wait for a DLCI configuration from the application.
 */
static void gsm_dlci_set_wait_config(struct gsm_dlci *dlci)
{}

/**
 *	gsm_dlci_begin_close	-	start channel open procedure
 *	@dlci: DLCI to open
 *
 *	Commence closing a DLCI from the Linux side. We issue DISC messages
 *	to the modem which should then reply with a UA, at which point we
 *	will move into closed state. Closing is done asynchronously with retry
 *	off timers. We may also receive a DM reply from the other end which
 *	indicates the channel was already closed.
 */

static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
{}

/**
 *	gsm_dlci_data		-	data arrived
 *	@dlci: channel
 *	@data: block of bytes received
 *	@clen: length of received block
 *
 *	A UI or UIH frame has arrived which contains data for a channel
 *	other than the control channel. If the relevant virtual tty is
 *	open we shovel the bits down it, if not we drop them.
 */

static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
{}

/**
 *	gsm_dlci_command	-	data arrived on control channel
 *	@dlci: channel
 *	@data: block of bytes received
 *	@len: length of received block
 *
 *	A UI or UIH frame has arrived which contains data for DLCI 0 the
 *	control channel. This should contain a command EA followed by
 *	control data bytes. The command EA contains a command/response bit
 *	and we divide up the work accordingly.
 */

static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len)
{}

/**
 *	gsm_kick_timer	-	transmit if possible
 *	@t: timer contained in our gsm object
 *
 *	Transmit data from DLCIs if the queue is empty. We can't rely on
 *	a tty wakeup except when we filled the pipe so we need to fire off
 *	new data ourselves in other cases.
 */
static void gsm_kick_timer(struct timer_list *t)
{}

/**
 * gsm_dlci_copy_config_values	-	copy DLCI configuration
 * @dlci: source DLCI
 * @dc: configuration structure to fill
 */
static void gsm_dlci_copy_config_values(struct gsm_dlci *dlci, struct gsm_dlci_config *dc)
{}

/**
 * gsm_dlci_config	-	configure DLCI from configuration
 * @dlci: DLCI to configure
 * @dc: DLCI configuration
 * @open: open DLCI after configuration?
 */
static int gsm_dlci_config(struct gsm_dlci *dlci, struct gsm_dlci_config *dc, int open)
{}

/*
 *	Allocate/Free DLCI channels
 */

/**
 *	gsm_dlci_alloc		-	allocate a DLCI
 *	@gsm: GSM mux
 *	@addr: address of the DLCI
 *
 *	Allocate and install a new DLCI object into the GSM mux.
 *
 *	FIXME: review locking races
 */

static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
{}

/**
 *	gsm_dlci_free		-	free DLCI
 *	@port: tty port for DLCI to free
 *
 *	Free up a DLCI.
 *
 *	Can sleep.
 */
static void gsm_dlci_free(struct tty_port *port)
{}

static inline void dlci_get(struct gsm_dlci *dlci)
{}

static inline void dlci_put(struct gsm_dlci *dlci)
{}

static void gsm_destroy_network(struct gsm_dlci *dlci);

/**
 *	gsm_dlci_release		-	release DLCI
 *	@dlci: DLCI to destroy
 *
 *	Release a DLCI. Actual free is deferred until either
 *	mux is closed or tty is closed - whichever is last.
 *
 *	Can sleep.
 */
static void gsm_dlci_release(struct gsm_dlci *dlci)
{}

/*
 *	LAPBish link layer logic
 */

/**
 *	gsm_queue		-	a GSM frame is ready to process
 *	@gsm: pointer to our gsm mux
 *
 *	At this point in time a frame has arrived and been demangled from
 *	the line encoding. All the differences between the encodings have
 *	been handled below us and the frame is unpacked into the structures.
 *	The fcs holds the header FCS but any data FCS must be added here.
 */

static void gsm_queue(struct gsm_mux *gsm)
{}

/**
 * gsm0_receive_state_check_and_fix	-	check and correct receive state
 * @gsm: gsm data for this ldisc instance
 *
 * Ensures that the current receive state is valid for basic option mode.
 */

static void gsm0_receive_state_check_and_fix(struct gsm_mux *gsm)
{}

/**
 *	gsm0_receive	-	perform processing for non-transparency
 *	@gsm: gsm data for this ldisc instance
 *	@c: character
 *
 *	Receive bytes in gsm mode 0
 */

static void gsm0_receive(struct gsm_mux *gsm, u8 c)
{}

/**
 * gsm1_receive_state_check_and_fix	-	check and correct receive state
 * @gsm: gsm data for this ldisc instance
 *
 * Ensures that the current receive state is valid for advanced option mode.
 */

static void gsm1_receive_state_check_and_fix(struct gsm_mux *gsm)
{}

/**
 *	gsm1_receive	-	perform processing for non-transparency
 *	@gsm: gsm data for this ldisc instance
 *	@c: character
 *
 *	Receive bytes in mode 1 (Advanced option)
 */

static void gsm1_receive(struct gsm_mux *gsm, u8 c)
{}

/**
 *	gsm_error		-	handle tty error
 *	@gsm: ldisc data
 *
 *	Handle an error in the receipt of data for a frame. Currently we just
 *	go back to hunting for a SOF.
 *
 *	FIXME: better diagnostics ?
 */

static void gsm_error(struct gsm_mux *gsm)
{}

/**
 *	gsm_cleanup_mux		-	generic GSM protocol cleanup
 *	@gsm: our mux
 *	@disc: disconnect link?
 *
 *	Clean up the bits of the mux which are the same for all framing
 *	protocols. Remove the mux from the mux table, stop all the timers
 *	and then shut down each device hanging up the channels as we go.
 */

static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
{}

/**
 *	gsm_activate_mux	-	generic GSM setup
 *	@gsm: our mux
 *
 *	Set up the bits of the mux which are the same for all framing
 *	protocols. Add the mux to the mux table so it can be opened and
 *	finally kick off connecting to DLCI 0 on the modem.
 */

static int gsm_activate_mux(struct gsm_mux *gsm)
{}

/**
 *	gsm_free_mux		-	free up a mux
 *	@gsm: mux to free
 *
 *	Dispose of allocated resources for a dead mux
 */
static void gsm_free_mux(struct gsm_mux *gsm)
{}

/**
 *	gsm_free_muxr		-	free up a mux
 *	@ref: kreference to the mux to free
 *
 *	Dispose of allocated resources for a dead mux
 */
static void gsm_free_muxr(struct kref *ref)
{}

static inline void mux_get(struct gsm_mux *gsm)
{}

static inline void mux_put(struct gsm_mux *gsm)
{}

static inline unsigned int mux_num_to_base(struct gsm_mux *gsm)
{}

static inline unsigned int mux_line_to_num(unsigned int line)
{}

/**
 *	gsm_alloc_mux		-	allocate a mux
 *
 *	Creates a new mux ready for activation.
 */

static struct gsm_mux *gsm_alloc_mux(void)
{}

static void gsm_copy_config_values(struct gsm_mux *gsm,
				   struct gsm_config *c)
{}

static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
{}

static void gsm_copy_config_ext_values(struct gsm_mux *gsm,
				       struct gsm_config_ext *ce)
{}

static int gsm_config_ext(struct gsm_mux *gsm, struct gsm_config_ext *ce)
{}

/**
 *	gsmld_output		-	write to link
 *	@gsm: our mux
 *	@data: bytes to output
 *	@len: size
 *
 *	Write a block of data from the GSM mux to the data channel. This
 *	will eventually be serialized from above but at the moment isn't.
 */

static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
{}


/**
 *	gsmld_write_trigger	-	schedule ldisc write task
 *	@gsm: our mux
 */
static void gsmld_write_trigger(struct gsm_mux *gsm)
{}


/**
 *	gsmld_write_task	-	ldisc write task
 *	@work: our tx write work
 *
 *	Writes out data to the ldisc if possible. We are doing this here to
 *	avoid dead-locking. This returns if no space or data is left for output.
 */
static void gsmld_write_task(struct work_struct *work)
{}

/**
 *	gsmld_attach_gsm	-	mode set up
 *	@tty: our tty structure
 *	@gsm: our mux
 *
 *	Set up the MUX for basic mode and commence connecting to the
 *	modem. Currently called from the line discipline set up but
 *	will need moving to an ioctl path.
 */

static void gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
{}

/**
 *	gsmld_detach_gsm	-	stop doing 0710 mux
 *	@tty: tty attached to the mux
 *	@gsm: mux
 *
 *	Shutdown and then clean up the resources used by the line discipline
 */

static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
{}

static void gsmld_receive_buf(struct tty_struct *tty, const u8 *cp,
			      const u8 *fp, size_t count)
{}

/**
 *	gsmld_flush_buffer	-	clean input queue
 *	@tty:	terminal device
 *
 *	Flush the input buffer. Called when the line discipline is
 *	being closed, when the tty layer wants the buffer flushed (eg
 *	at hangup).
 */

static void gsmld_flush_buffer(struct tty_struct *tty)
{}

/**
 *	gsmld_close		-	close the ldisc for this tty
 *	@tty: device
 *
 *	Called from the terminal layer when this line discipline is
 *	being shut down, either because of a close or becsuse of a
 *	discipline change. The function will not be called while other
 *	ldisc methods are in progress.
 */

static void gsmld_close(struct tty_struct *tty)
{}

/**
 *	gsmld_open		-	open an ldisc
 *	@tty: terminal to open
 *
 *	Called when this line discipline is being attached to the
 *	terminal device. Can sleep. Called serialized so that no
 *	other events will occur in parallel. No further open will occur
 *	until a close.
 */

static int gsmld_open(struct tty_struct *tty)
{}

/**
 *	gsmld_write_wakeup	-	asynchronous I/O notifier
 *	@tty: tty device
 *
 *	Required for the ptys, serial driver etc. since processes
 *	that attach themselves to the master and rely on ASYNC
 *	IO must be woken up
 */

static void gsmld_write_wakeup(struct tty_struct *tty)
{}

/**
 *	gsmld_read		-	read function for tty
 *	@tty: tty device
 *	@file: file object
 *	@buf: userspace buffer pointer
 *	@nr: size of I/O
 *	@cookie: unused
 *	@offset: unused
 *
 *	Perform reads for the line discipline. We are guaranteed that the
 *	line discipline will not be closed under us but we may get multiple
 *	parallel readers and must handle this ourselves. We may also get
 *	a hangup. Always called in user context, may sleep.
 *
 *	This code must be sure never to sleep through a hangup.
 */

static ssize_t gsmld_read(struct tty_struct *tty, struct file *file, u8 *buf,
			  size_t nr, void **cookie, unsigned long offset)
{}

/**
 *	gsmld_write		-	write function for tty
 *	@tty: tty device
 *	@file: file object
 *	@buf: userspace buffer pointer
 *	@nr: size of I/O
 *
 *	Called when the owner of the device wants to send a frame
 *	itself (or some other control data). The data is transferred
 *	as-is and must be properly framed and checksummed as appropriate
 *	by userspace. Frames are either sent whole or not at all as this
 *	avoids pain user side.
 */

static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
			   const u8 *buf, size_t nr)
{}

/**
 *	gsmld_poll		-	poll method for N_GSM0710
 *	@tty: terminal device
 *	@file: file accessing it
 *	@wait: poll table
 *
 *	Called when the line discipline is asked to poll() for data or
 *	for special events. This code is not serialized with respect to
 *	other events save open/close.
 *
 *	This code must be sure never to sleep through a hangup.
 *	Called without the kernel lock held - fine
 */

static __poll_t gsmld_poll(struct tty_struct *tty, struct file *file,
							poll_table *wait)
{}

static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
		       unsigned long arg)
{}

/*
 *	Network interface
 *
 */

static int gsm_mux_net_open(struct net_device *net)
{}

static int gsm_mux_net_close(struct net_device *net)
{}

static void dlci_net_free(struct gsm_dlci *dlci)
{}
static void net_free(struct kref *ref)
{}

static inline void muxnet_get(struct gsm_mux_net *mux_net)
{}

static inline void muxnet_put(struct gsm_mux_net *mux_net)
{}

static netdev_tx_t gsm_mux_net_start_xmit(struct sk_buff *skb,
				      struct net_device *net)
{}

/* called when a packet did not ack after watchdogtimeout */
static void gsm_mux_net_tx_timeout(struct net_device *net, unsigned int txqueue)
{}

static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, const u8 *in_buf, int size)
{}

static void gsm_mux_net_init(struct net_device *net)
{}


/* caller holds the dlci mutex */
static void gsm_destroy_network(struct gsm_dlci *dlci)
{}


/* caller holds the dlci mutex */
static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
{}

/* Line discipline for real tty */
static struct tty_ldisc_ops tty_ldisc_packet =;

/*
 *	Virtual tty side
 */

/**
 *	gsm_modem_upd_via_data	-	send modem bits via convergence layer
 *	@dlci: channel
 *	@brk: break signal
 *
 *	Send an empty frame to signal mobile state changes and to transmit the
 *	break signal for adaption 2.
 */

static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
{}

/**
 *	gsm_modem_upd_via_msc	-	send modem bits via control frame
 *	@dlci: channel
 *	@brk: break signal
 */

static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
{}

/**
 *	gsm_modem_update	-	send modem status line state
 *	@dlci: channel
 *	@brk: break signal
 */

static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
{}

/**
 * gsm_wait_modem_change - wait for modem status line change
 * @dlci: channel
 * @mask: modem status line bits
 *
 * The function returns if:
 * - any given modem status line bit changed
 * - the wait event function got interrupted (e.g. by a signal)
 * - the underlying DLCI was closed
 * - the underlying ldisc device was removed
 */
static int gsm_wait_modem_change(struct gsm_dlci *dlci, u32 mask)
{}

static bool gsm_carrier_raised(struct tty_port *port)
{}

static void gsm_dtr_rts(struct tty_port *port, bool active)
{}

static const struct tty_port_operations gsm_port_ops =;

static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
{}

static int gsmtty_open(struct tty_struct *tty, struct file *filp)
{}

static void gsmtty_close(struct tty_struct *tty, struct file *filp)
{}

static void gsmtty_hangup(struct tty_struct *tty)
{}

static ssize_t gsmtty_write(struct tty_struct *tty, const u8 *buf, size_t len)
{}

static unsigned int gsmtty_write_room(struct tty_struct *tty)
{}

static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty)
{}

static void gsmtty_flush_buffer(struct tty_struct *tty)
{}

static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
{}

static int gsmtty_tiocmget(struct tty_struct *tty)
{}

static int gsmtty_tiocmset(struct tty_struct *tty,
	unsigned int set, unsigned int clear)
{}


static int gsmtty_ioctl(struct tty_struct *tty,
			unsigned int cmd, unsigned long arg)
{}

static void gsmtty_set_termios(struct tty_struct *tty,
			       const struct ktermios *old)
{}

static void gsmtty_throttle(struct tty_struct *tty)
{}

static void gsmtty_unthrottle(struct tty_struct *tty)
{}

static int gsmtty_break_ctl(struct tty_struct *tty, int state)
{}

static void gsmtty_cleanup(struct tty_struct *tty)
{}

/* Virtual ttys for the demux */
static const struct tty_operations gsmtty_ops =;



static int __init gsm_init(void)
{}

static void __exit gsm_exit(void)
{}

module_init();
module_exit(gsm_exit);


MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_ALIAS_LDISC();