cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rose_link.c (6592B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *
      4 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
      5 */
      6#include <linux/errno.h>
      7#include <linux/types.h>
      8#include <linux/socket.h>
      9#include <linux/in.h>
     10#include <linux/kernel.h>
     11#include <linux/jiffies.h>
     12#include <linux/timer.h>
     13#include <linux/string.h>
     14#include <linux/sockios.h>
     15#include <linux/net.h>
     16#include <linux/slab.h>
     17#include <net/ax25.h>
     18#include <linux/inet.h>
     19#include <linux/netdevice.h>
     20#include <linux/skbuff.h>
     21#include <net/sock.h>
     22#include <linux/fcntl.h>
     23#include <linux/mm.h>
     24#include <linux/interrupt.h>
     25#include <net/rose.h>
     26
     27static void rose_ftimer_expiry(struct timer_list *);
     28static void rose_t0timer_expiry(struct timer_list *);
     29
     30static void rose_transmit_restart_confirmation(struct rose_neigh *neigh);
     31static void rose_transmit_restart_request(struct rose_neigh *neigh);
     32
     33void rose_start_ftimer(struct rose_neigh *neigh)
     34{
     35	del_timer(&neigh->ftimer);
     36
     37	neigh->ftimer.function = rose_ftimer_expiry;
     38	neigh->ftimer.expires  =
     39		jiffies + msecs_to_jiffies(sysctl_rose_link_fail_timeout);
     40
     41	add_timer(&neigh->ftimer);
     42}
     43
     44static void rose_start_t0timer(struct rose_neigh *neigh)
     45{
     46	del_timer(&neigh->t0timer);
     47
     48	neigh->t0timer.function = rose_t0timer_expiry;
     49	neigh->t0timer.expires  =
     50		jiffies + msecs_to_jiffies(sysctl_rose_restart_request_timeout);
     51
     52	add_timer(&neigh->t0timer);
     53}
     54
     55void rose_stop_ftimer(struct rose_neigh *neigh)
     56{
     57	del_timer(&neigh->ftimer);
     58}
     59
     60void rose_stop_t0timer(struct rose_neigh *neigh)
     61{
     62	del_timer(&neigh->t0timer);
     63}
     64
     65int rose_ftimer_running(struct rose_neigh *neigh)
     66{
     67	return timer_pending(&neigh->ftimer);
     68}
     69
     70static int rose_t0timer_running(struct rose_neigh *neigh)
     71{
     72	return timer_pending(&neigh->t0timer);
     73}
     74
     75static void rose_ftimer_expiry(struct timer_list *t)
     76{
     77}
     78
     79static void rose_t0timer_expiry(struct timer_list *t)
     80{
     81	struct rose_neigh *neigh = from_timer(neigh, t, t0timer);
     82
     83	rose_transmit_restart_request(neigh);
     84
     85	neigh->dce_mode = 0;
     86
     87	rose_start_t0timer(neigh);
     88}
     89
     90/*
     91 *	Interface to ax25_send_frame. Changes my level 2 callsign depending
     92 *	on whether we have a global ROSE callsign or use the default port
     93 *	callsign.
     94 */
     95static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
     96{
     97	const ax25_address *rose_call;
     98	ax25_cb *ax25s;
     99
    100	if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
    101		rose_call = (const ax25_address *)neigh->dev->dev_addr;
    102	else
    103		rose_call = &rose_callsign;
    104
    105	ax25s = neigh->ax25;
    106	neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
    107	if (ax25s)
    108		ax25_cb_put(ax25s);
    109
    110	return neigh->ax25 != NULL;
    111}
    112
    113/*
    114 *	Interface to ax25_link_up. Changes my level 2 callsign depending
    115 *	on whether we have a global ROSE callsign or use the default port
    116 *	callsign.
    117 */
    118static int rose_link_up(struct rose_neigh *neigh)
    119{
    120	const ax25_address *rose_call;
    121	ax25_cb *ax25s;
    122
    123	if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
    124		rose_call = (const ax25_address *)neigh->dev->dev_addr;
    125	else
    126		rose_call = &rose_callsign;
    127
    128	ax25s = neigh->ax25;
    129	neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
    130	if (ax25s)
    131		ax25_cb_put(ax25s);
    132
    133	return neigh->ax25 != NULL;
    134}
    135
    136/*
    137 *	This handles all restart and diagnostic frames.
    138 */
    139void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigned short frametype)
    140{
    141	struct sk_buff *skbn;
    142
    143	switch (frametype) {
    144	case ROSE_RESTART_REQUEST:
    145		rose_stop_t0timer(neigh);
    146		neigh->restarted = 1;
    147		neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
    148		rose_transmit_restart_confirmation(neigh);
    149		break;
    150
    151	case ROSE_RESTART_CONFIRMATION:
    152		rose_stop_t0timer(neigh);
    153		neigh->restarted = 1;
    154		break;
    155
    156	case ROSE_DIAGNOSTIC:
    157		pr_warn("ROSE: received diagnostic #%d - %3ph\n", skb->data[3],
    158			skb->data + 4);
    159		break;
    160
    161	default:
    162		printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype);
    163		break;
    164	}
    165
    166	if (neigh->restarted) {
    167		while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
    168			if (!rose_send_frame(skbn, neigh))
    169				kfree_skb(skbn);
    170	}
    171}
    172
    173/*
    174 *	This routine is called when a Restart Request is needed
    175 */
    176static void rose_transmit_restart_request(struct rose_neigh *neigh)
    177{
    178	struct sk_buff *skb;
    179	unsigned char *dptr;
    180	int len;
    181
    182	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
    183
    184	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
    185		return;
    186
    187	skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
    188
    189	dptr = skb_put(skb, ROSE_MIN_LEN + 3);
    190
    191	*dptr++ = AX25_P_ROSE;
    192	*dptr++ = ROSE_GFI;
    193	*dptr++ = 0x00;
    194	*dptr++ = ROSE_RESTART_REQUEST;
    195	*dptr++ = ROSE_DTE_ORIGINATED;
    196	*dptr++ = 0;
    197
    198	if (!rose_send_frame(skb, neigh))
    199		kfree_skb(skb);
    200}
    201
    202/*
    203 * This routine is called when a Restart Confirmation is needed
    204 */
    205static void rose_transmit_restart_confirmation(struct rose_neigh *neigh)
    206{
    207	struct sk_buff *skb;
    208	unsigned char *dptr;
    209	int len;
    210
    211	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
    212
    213	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
    214		return;
    215
    216	skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
    217
    218	dptr = skb_put(skb, ROSE_MIN_LEN + 1);
    219
    220	*dptr++ = AX25_P_ROSE;
    221	*dptr++ = ROSE_GFI;
    222	*dptr++ = 0x00;
    223	*dptr++ = ROSE_RESTART_CONFIRMATION;
    224
    225	if (!rose_send_frame(skb, neigh))
    226		kfree_skb(skb);
    227}
    228
    229/*
    230 * This routine is called when a Clear Request is needed outside of the context
    231 * of a connected socket.
    232 */
    233void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic)
    234{
    235	struct sk_buff *skb;
    236	unsigned char *dptr;
    237	int len;
    238
    239	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
    240
    241	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
    242		return;
    243
    244	skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
    245
    246	dptr = skb_put(skb, ROSE_MIN_LEN + 3);
    247
    248	*dptr++ = AX25_P_ROSE;
    249	*dptr++ = ((lci >> 8) & 0x0F) | ROSE_GFI;
    250	*dptr++ = ((lci >> 0) & 0xFF);
    251	*dptr++ = ROSE_CLEAR_REQUEST;
    252	*dptr++ = cause;
    253	*dptr++ = diagnostic;
    254
    255	if (!rose_send_frame(skb, neigh))
    256		kfree_skb(skb);
    257}
    258
    259void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
    260{
    261	unsigned char *dptr;
    262
    263	if (neigh->loopback) {
    264		rose_loopback_queue(skb, neigh);
    265		return;
    266	}
    267
    268	if (!rose_link_up(neigh))
    269		neigh->restarted = 0;
    270
    271	dptr = skb_push(skb, 1);
    272	*dptr++ = AX25_P_ROSE;
    273
    274	if (neigh->restarted) {
    275		if (!rose_send_frame(skb, neigh))
    276			kfree_skb(skb);
    277	} else {
    278		skb_queue_tail(&neigh->queue, skb);
    279
    280		if (!rose_t0timer_running(neigh)) {
    281			rose_transmit_restart_request(neigh);
    282			neigh->dce_mode = 0;
    283			rose_start_t0timer(neigh);
    284		}
    285	}
    286}