// SPDX-License-Identifier: GPL-2.0-only /* * 6pack.c This module implements the 6pack protocol for kernel-based * devices like TTY. It interfaces between a raw TTY and the * kernel's AX.25 protocol layers. * * Authors: Andreas Könsgen <ajk@comnets.uni-bremen.de> * Ralf Baechle DL5RB <ralf@linux-mips.org> * * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by * * Laurence Culhane, <loz@holmes.demon.co.uk> * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*/
/* default level 2 parameters */ #define SIXP_TXDELAY 25 /* 250 ms */ #define SIXP_PERSIST 50 /* in 256ths */ #define SIXP_SLOTTIME 10 /* 100 ms */ #define SIXP_INIT_RESYNC_TIMEOUT (3*HZ/2) /* in 1 s */ #define SIXP_RESYNC_TIMEOUT 5*HZ /* in 1 s */
/* 6pack configuration. */ #define SIXP_NRUNIT 31 /* MAX number of 6pack channels */ #define SIXP_MTU 256 /* Default MTU */
enum sixpack_flags {
SIXPF_ERROR, /* Parity, etc. error */
};
struct sixpack { /* Various fields. */ struct tty_struct *tty; /* ptr to TTY structure */ struct net_device *dev; /* easy for intr handling */
/* These are pointers to the malloc()ed frame buffers. */ int rcount; /* received chars counter */ unsignedchar *xbuff; /* transmitter buffer */ unsignedchar *xhead; /* next byte to XMIT */ int xleft; /* bytes left in XMIT queue */
/* * Perform the persistence/slottime algorithm for CSMA access. If the * persistence check was successful, write the data to the serial driver. * Note that in case of DAMA operation, the data is not sent here.
*/
staticvoid sp_xmit_on_air(struct timer_list *t)
{ struct sixpack *sp = timer_container_of(sp, t, tx_t); int actual, when = sp->slottime; staticunsignedchar random;
/* ----> 6pack timer interrupt handler and friends. <---- */
/* Encapsulate one AX.25 frame and stuff into a TTY queue. */ staticvoid sp_encaps(struct sixpack *sp, unsignedchar *icp, int len)
{ unsignedchar *msg, *p = icp; int actual, count;
switch (p[0]) { case 1: sp->tx_delay = p[1]; return; case 2: sp->persistence = p[1]; return; case 3: sp->slottime = p[1]; return; case 4: /* ignored */ return; case 5: sp->duplex = p[1]; return;
}
if (p[0] != 0) return;
/* * In case of fullduplex or DAMA operation, we don't take care about the * state of the DCD or of any timers, as the determination of the * correct time to send is the job of the AX.25 layer. We send * immediately after data has arrived.
*/ if (sp->duplex == 1) {
sp->led_state = 0x70;
sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
actual = sp->tty->ops->write(sp->tty, sp->xbuff, count);
sp->xleft = count - actual;
sp->xhead = sp->xbuff + actual;
sp->led_state = 0x60;
sp->tty->ops->write(sp->tty, &sp->led_state, 1);
} else {
sp->xleft = count;
sp->xhead = sp->xbuff;
sp->status2 = count;
sp_xmit_on_air(&sp->tx_t);
}
if (skb->protocol == htons(ETH_P_IP)) return ax25_ip_xmit(skb);
spin_lock_bh(&sp->lock); /* We were not busy, so we are now... :-) */
netif_stop_queue(dev);
dev->stats.tx_bytes += skb->len;
sp_encaps(sp, skb->data, skb->len);
spin_unlock_bh(&sp->lock);
/* * Called by the TTY driver when there's room for more data. If we have * more packets to send, we send them here.
*/ staticvoid sixpack_write_wakeup(struct tty_struct *tty)
{ struct sixpack *sp = tty->disc_data; int actual;
if (!sp) return; if (sp->xleft <= 0) { /* Now serial buffer is almost free & we can start
* transmission of another packet */
sp->dev->stats.tx_packets++;
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sp->tx_enable = 0;
netif_wake_queue(sp->dev); return;
}
if (sp->tx_enable) {
actual = tty->ops->write(tty, sp->xhead, sp->xleft);
sp->xleft -= actual;
sp->xhead += actual;
}
}
/* * Handle the 'receiver data ready' interrupt. * This function is called by the tty module in the kernel when * a block of 6pack data has been received, which can now be decapsulated * and sent on to some IP layer for further processing.
*/ staticvoid sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp, size_t count)
{ struct sixpack *sp;
size_t count1;
if (!count) return;
sp = tty->disc_data; if (!sp) return;
/* Read the characters out of the buffer */
count1 = count; while (count) {
count--; if (fp && *fp++) { if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
sp->dev->stats.rx_errors++; continue;
}
}
sixpack_decode(sp, cp, count1);
tty_unthrottle(tty);
}
/* * Try to resync the TNC. Called by the resync timer defined in * decode_prio_command
*/
/* * Open the high-level part of the 6pack channel. * This function is called by the TTY module when the * 6pack line discipline is called for. Because we are * sure the tty line exists, we only have to link it to * a free 6pcack channel...
*/ staticint sixpack_open(struct tty_struct *tty)
{ char *xbuff = NULL; struct net_device *dev; struct sixpack *sp; unsignedlong len; int err = 0;
if (!capable(CAP_NET_ADMIN)) return -EPERM; if (tty->ops->write == NULL) return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct sixpack), "sp%d", NET_NAME_UNKNOWN,
sp_setup); if (!dev) {
err = -ENOMEM; goto out;
}
/* Done. We have linked the TTY line to a channel. */
tty->disc_data = sp;
tty->receive_room = 65536;
/* Now we're ready to register. */
err = register_netdev(dev); if (err) goto out_free;
tnc_init(sp);
return 0;
out_free:
kfree(xbuff);
free_netdev(dev);
out: return err;
}
/* * Close down a 6pack channel. * This means flushing out any pending queues, and then restoring the * TTY line discipline to what it was before it got hooked to 6pack * (which usually is TTY again).
*/ staticvoid sixpack_close(struct tty_struct *tty)
{ struct sixpack *sp;
sp = tty->disc_data; if (!sp) return;
tty->disc_data = NULL;
/* We must stop the queue to avoid potentially scribbling * on the free buffers. The sp->dead completion is not sufficient * to protect us from sp->xbuff access.
*/
netif_stop_queue(sp->dev);
/* Initialize 6pack control device -- register 6pack line discipline */
staticint __init sixpack_init_driver(void)
{ int status;
/* Register the provided line protocol discipline */
status = tty_register_ldisc(&sp_ldisc); if (status)
pr_err("6pack: can't register line discipline (err = %d)\n", status);
/* RX and DCD flags can only be set in the same prio command, if the DCD flag has been set without the RX flag in the previous prio command. If DCD has not been set before, something in the transmission has gone wrong. In this case, RX and DCD are cleared in order to prevent the decode_data routine from
reading further data that might be corrupt. */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.