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

nr_in.c (6906B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *
      4 * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
      5 * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
      6 */
      7#include <linux/errno.h>
      8#include <linux/types.h>
      9#include <linux/socket.h>
     10#include <linux/in.h>
     11#include <linux/kernel.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 <net/tcp_states.h>
     23#include <linux/uaccess.h>
     24#include <linux/fcntl.h>
     25#include <linux/mm.h>
     26#include <linux/interrupt.h>
     27#include <net/netrom.h>
     28
     29static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
     30{
     31	struct sk_buff *skbo, *skbn = skb;
     32	struct nr_sock *nr = nr_sk(sk);
     33
     34	skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
     35
     36	nr_start_idletimer(sk);
     37
     38	if (more) {
     39		nr->fraglen += skb->len;
     40		skb_queue_tail(&nr->frag_queue, skb);
     41		return 0;
     42	}
     43
     44	if (!more && nr->fraglen > 0) {	/* End of fragment */
     45		nr->fraglen += skb->len;
     46		skb_queue_tail(&nr->frag_queue, skb);
     47
     48		if ((skbn = alloc_skb(nr->fraglen, GFP_ATOMIC)) == NULL)
     49			return 1;
     50
     51		skb_reset_transport_header(skbn);
     52
     53		while ((skbo = skb_dequeue(&nr->frag_queue)) != NULL) {
     54			skb_copy_from_linear_data(skbo,
     55						  skb_put(skbn, skbo->len),
     56						  skbo->len);
     57			kfree_skb(skbo);
     58		}
     59
     60		nr->fraglen = 0;
     61	}
     62
     63	return sock_queue_rcv_skb(sk, skbn);
     64}
     65
     66/*
     67 * State machine for state 1, Awaiting Connection State.
     68 * The handling of the timer(s) is in file nr_timer.c.
     69 * Handling of state 0 and connection release is in netrom.c.
     70 */
     71static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
     72	int frametype)
     73{
     74	switch (frametype) {
     75	case NR_CONNACK: {
     76		struct nr_sock *nr = nr_sk(sk);
     77
     78		nr_stop_t1timer(sk);
     79		nr_start_idletimer(sk);
     80		nr->your_index = skb->data[17];
     81		nr->your_id    = skb->data[18];
     82		nr->vs	       = 0;
     83		nr->va	       = 0;
     84		nr->vr	       = 0;
     85		nr->vl	       = 0;
     86		nr->state      = NR_STATE_3;
     87		nr->n2count    = 0;
     88		nr->window     = skb->data[20];
     89		sk->sk_state   = TCP_ESTABLISHED;
     90		if (!sock_flag(sk, SOCK_DEAD))
     91			sk->sk_state_change(sk);
     92		break;
     93	}
     94
     95	case NR_CONNACK | NR_CHOKE_FLAG:
     96		nr_disconnect(sk, ECONNREFUSED);
     97		break;
     98
     99	case NR_RESET:
    100		if (sysctl_netrom_reset_circuit)
    101			nr_disconnect(sk, ECONNRESET);
    102		break;
    103
    104	default:
    105		break;
    106	}
    107	return 0;
    108}
    109
    110/*
    111 * State machine for state 2, Awaiting Release State.
    112 * The handling of the timer(s) is in file nr_timer.c
    113 * Handling of state 0 and connection release is in netrom.c.
    114 */
    115static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
    116	int frametype)
    117{
    118	switch (frametype) {
    119	case NR_CONNACK | NR_CHOKE_FLAG:
    120		nr_disconnect(sk, ECONNRESET);
    121		break;
    122
    123	case NR_DISCREQ:
    124		nr_write_internal(sk, NR_DISCACK);
    125		fallthrough;
    126	case NR_DISCACK:
    127		nr_disconnect(sk, 0);
    128		break;
    129
    130	case NR_RESET:
    131		if (sysctl_netrom_reset_circuit)
    132			nr_disconnect(sk, ECONNRESET);
    133		break;
    134
    135	default:
    136		break;
    137	}
    138	return 0;
    139}
    140
    141/*
    142 * State machine for state 3, Connected State.
    143 * The handling of the timer(s) is in file nr_timer.c
    144 * Handling of state 0 and connection release is in netrom.c.
    145 */
    146static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype)
    147{
    148	struct nr_sock *nrom = nr_sk(sk);
    149	struct sk_buff_head temp_queue;
    150	struct sk_buff *skbn;
    151	unsigned short save_vr;
    152	unsigned short nr, ns;
    153	int queued = 0;
    154
    155	nr = skb->data[18];
    156
    157	switch (frametype) {
    158	case NR_CONNREQ:
    159		nr_write_internal(sk, NR_CONNACK);
    160		break;
    161
    162	case NR_DISCREQ:
    163		nr_write_internal(sk, NR_DISCACK);
    164		nr_disconnect(sk, 0);
    165		break;
    166
    167	case NR_CONNACK | NR_CHOKE_FLAG:
    168	case NR_DISCACK:
    169		nr_disconnect(sk, ECONNRESET);
    170		break;
    171
    172	case NR_INFOACK:
    173	case NR_INFOACK | NR_CHOKE_FLAG:
    174	case NR_INFOACK | NR_NAK_FLAG:
    175	case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
    176		if (frametype & NR_CHOKE_FLAG) {
    177			nrom->condition |= NR_COND_PEER_RX_BUSY;
    178			nr_start_t4timer(sk);
    179		} else {
    180			nrom->condition &= ~NR_COND_PEER_RX_BUSY;
    181			nr_stop_t4timer(sk);
    182		}
    183		if (!nr_validate_nr(sk, nr)) {
    184			break;
    185		}
    186		if (frametype & NR_NAK_FLAG) {
    187			nr_frames_acked(sk, nr);
    188			nr_send_nak_frame(sk);
    189		} else {
    190			if (nrom->condition & NR_COND_PEER_RX_BUSY) {
    191				nr_frames_acked(sk, nr);
    192			} else {
    193				nr_check_iframes_acked(sk, nr);
    194			}
    195		}
    196		break;
    197
    198	case NR_INFO:
    199	case NR_INFO | NR_NAK_FLAG:
    200	case NR_INFO | NR_CHOKE_FLAG:
    201	case NR_INFO | NR_MORE_FLAG:
    202	case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
    203	case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
    204	case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
    205	case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
    206		if (frametype & NR_CHOKE_FLAG) {
    207			nrom->condition |= NR_COND_PEER_RX_BUSY;
    208			nr_start_t4timer(sk);
    209		} else {
    210			nrom->condition &= ~NR_COND_PEER_RX_BUSY;
    211			nr_stop_t4timer(sk);
    212		}
    213		if (nr_validate_nr(sk, nr)) {
    214			if (frametype & NR_NAK_FLAG) {
    215				nr_frames_acked(sk, nr);
    216				nr_send_nak_frame(sk);
    217			} else {
    218				if (nrom->condition & NR_COND_PEER_RX_BUSY) {
    219					nr_frames_acked(sk, nr);
    220				} else {
    221					nr_check_iframes_acked(sk, nr);
    222				}
    223			}
    224		}
    225		queued = 1;
    226		skb_queue_head(&nrom->reseq_queue, skb);
    227		if (nrom->condition & NR_COND_OWN_RX_BUSY)
    228			break;
    229		skb_queue_head_init(&temp_queue);
    230		do {
    231			save_vr = nrom->vr;
    232			while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) {
    233				ns = skbn->data[17];
    234				if (ns == nrom->vr) {
    235					if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
    236						nrom->vr = (nrom->vr + 1) % NR_MODULUS;
    237					} else {
    238						nrom->condition |= NR_COND_OWN_RX_BUSY;
    239						skb_queue_tail(&temp_queue, skbn);
    240					}
    241				} else if (nr_in_rx_window(sk, ns)) {
    242					skb_queue_tail(&temp_queue, skbn);
    243				} else {
    244					kfree_skb(skbn);
    245				}
    246			}
    247			while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
    248				skb_queue_tail(&nrom->reseq_queue, skbn);
    249			}
    250		} while (save_vr != nrom->vr);
    251		/*
    252		 * Window is full, ack it immediately.
    253		 */
    254		if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) {
    255			nr_enquiry_response(sk);
    256		} else {
    257			if (!(nrom->condition & NR_COND_ACK_PENDING)) {
    258				nrom->condition |= NR_COND_ACK_PENDING;
    259				nr_start_t2timer(sk);
    260			}
    261		}
    262		break;
    263
    264	case NR_RESET:
    265		if (sysctl_netrom_reset_circuit)
    266			nr_disconnect(sk, ECONNRESET);
    267		break;
    268
    269	default:
    270		break;
    271	}
    272	return queued;
    273}
    274
    275/* Higher level upcall for a LAPB frame - called with sk locked */
    276int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
    277{
    278	struct nr_sock *nr = nr_sk(sk);
    279	int queued = 0, frametype;
    280
    281	if (nr->state == NR_STATE_0)
    282		return 0;
    283
    284	frametype = skb->data[19];
    285
    286	switch (nr->state) {
    287	case NR_STATE_1:
    288		queued = nr_state1_machine(sk, skb, frametype);
    289		break;
    290	case NR_STATE_2:
    291		queued = nr_state2_machine(sk, skb, frametype);
    292		break;
    293	case NR_STATE_3:
    294		queued = nr_state3_machine(sk, skb, frametype);
    295		break;
    296	}
    297
    298	nr_kick(sk);
    299
    300	return queued;
    301}