18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Most of this code is based on the SDL diagrams published in the 7th ARRL 78c2ecf20Sopenharmony_ci * Computer Networking Conference papers. The diagrams have mistakes in them, 88c2ecf20Sopenharmony_ci * but are mostly correct. Before you modify the code could you read the SDL 98c2ecf20Sopenharmony_ci * diagrams as the code is not obvious and probably very easy to break. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/socket.h> 148c2ecf20Sopenharmony_ci#include <linux/in.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/timer.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/sockios.h> 198c2ecf20Sopenharmony_ci#include <linux/net.h> 208c2ecf20Sopenharmony_ci#include <net/ax25.h> 218c2ecf20Sopenharmony_ci#include <linux/inet.h> 228c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 248c2ecf20Sopenharmony_ci#include <net/sock.h> 258c2ecf20Sopenharmony_ci#include <net/tcp_states.h> 268c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 278c2ecf20Sopenharmony_ci#include <linux/mm.h> 288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 298c2ecf20Sopenharmony_ci#include <net/rose.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * State machine for state 1, Awaiting Call Accepted State. 338c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file rose_timer.c. 348c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_rose.c. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistatic int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci switch (frametype) { 418c2ecf20Sopenharmony_ci case ROSE_CALL_ACCEPTED: 428c2ecf20Sopenharmony_ci rose_stop_timer(sk); 438c2ecf20Sopenharmony_ci rose_start_idletimer(sk); 448c2ecf20Sopenharmony_ci rose->condition = 0x00; 458c2ecf20Sopenharmony_ci rose->vs = 0; 468c2ecf20Sopenharmony_ci rose->va = 0; 478c2ecf20Sopenharmony_ci rose->vr = 0; 488c2ecf20Sopenharmony_ci rose->vl = 0; 498c2ecf20Sopenharmony_ci rose->state = ROSE_STATE_3; 508c2ecf20Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 518c2ecf20Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 528c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci case ROSE_CLEAR_REQUEST: 568c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); 578c2ecf20Sopenharmony_ci rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); 588c2ecf20Sopenharmony_ci rose->neighbour->use--; 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci default: 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return 0; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * State machine for state 2, Awaiting Clear Confirmation State. 708c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file rose_timer.c 718c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_rose.c. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_cistatic int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci switch (frametype) { 788c2ecf20Sopenharmony_ci case ROSE_CLEAR_REQUEST: 798c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); 808c2ecf20Sopenharmony_ci rose_disconnect(sk, 0, skb->data[3], skb->data[4]); 818c2ecf20Sopenharmony_ci rose->neighbour->use--; 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci case ROSE_CLEAR_CONFIRMATION: 858c2ecf20Sopenharmony_ci rose_disconnect(sk, 0, -1, -1); 868c2ecf20Sopenharmony_ci rose->neighbour->use--; 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci default: 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * State machine for state 3, Connected State. 988c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file rose_timer.c 998c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_rose.c. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistatic int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 1048c2ecf20Sopenharmony_ci int queued = 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci switch (frametype) { 1078c2ecf20Sopenharmony_ci case ROSE_RESET_REQUEST: 1088c2ecf20Sopenharmony_ci rose_stop_timer(sk); 1098c2ecf20Sopenharmony_ci rose_start_idletimer(sk); 1108c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_RESET_CONFIRMATION); 1118c2ecf20Sopenharmony_ci rose->condition = 0x00; 1128c2ecf20Sopenharmony_ci rose->vs = 0; 1138c2ecf20Sopenharmony_ci rose->vr = 0; 1148c2ecf20Sopenharmony_ci rose->va = 0; 1158c2ecf20Sopenharmony_ci rose->vl = 0; 1168c2ecf20Sopenharmony_ci rose_requeue_frames(sk); 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci case ROSE_CLEAR_REQUEST: 1208c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); 1218c2ecf20Sopenharmony_ci rose_disconnect(sk, 0, skb->data[3], skb->data[4]); 1228c2ecf20Sopenharmony_ci rose->neighbour->use--; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci case ROSE_RR: 1268c2ecf20Sopenharmony_ci case ROSE_RNR: 1278c2ecf20Sopenharmony_ci if (!rose_validate_nr(sk, nr)) { 1288c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_RESET_REQUEST); 1298c2ecf20Sopenharmony_ci rose->condition = 0x00; 1308c2ecf20Sopenharmony_ci rose->vs = 0; 1318c2ecf20Sopenharmony_ci rose->vr = 0; 1328c2ecf20Sopenharmony_ci rose->va = 0; 1338c2ecf20Sopenharmony_ci rose->vl = 0; 1348c2ecf20Sopenharmony_ci rose->state = ROSE_STATE_4; 1358c2ecf20Sopenharmony_ci rose_start_t2timer(sk); 1368c2ecf20Sopenharmony_ci rose_stop_idletimer(sk); 1378c2ecf20Sopenharmony_ci } else { 1388c2ecf20Sopenharmony_ci rose_frames_acked(sk, nr); 1398c2ecf20Sopenharmony_ci if (frametype == ROSE_RNR) { 1408c2ecf20Sopenharmony_ci rose->condition |= ROSE_COND_PEER_RX_BUSY; 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci rose->condition &= ~ROSE_COND_PEER_RX_BUSY; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci case ROSE_DATA: /* XXX */ 1488c2ecf20Sopenharmony_ci rose->condition &= ~ROSE_COND_PEER_RX_BUSY; 1498c2ecf20Sopenharmony_ci if (!rose_validate_nr(sk, nr)) { 1508c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_RESET_REQUEST); 1518c2ecf20Sopenharmony_ci rose->condition = 0x00; 1528c2ecf20Sopenharmony_ci rose->vs = 0; 1538c2ecf20Sopenharmony_ci rose->vr = 0; 1548c2ecf20Sopenharmony_ci rose->va = 0; 1558c2ecf20Sopenharmony_ci rose->vl = 0; 1568c2ecf20Sopenharmony_ci rose->state = ROSE_STATE_4; 1578c2ecf20Sopenharmony_ci rose_start_t2timer(sk); 1588c2ecf20Sopenharmony_ci rose_stop_idletimer(sk); 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci rose_frames_acked(sk, nr); 1628c2ecf20Sopenharmony_ci if (ns == rose->vr) { 1638c2ecf20Sopenharmony_ci rose_start_idletimer(sk); 1648c2ecf20Sopenharmony_ci if (sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN) == 0 && 1658c2ecf20Sopenharmony_ci __sock_queue_rcv_skb(sk, skb) == 0) { 1668c2ecf20Sopenharmony_ci rose->vr = (rose->vr + 1) % ROSE_MODULUS; 1678c2ecf20Sopenharmony_ci queued = 1; 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci /* Should never happen ! */ 1708c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_RESET_REQUEST); 1718c2ecf20Sopenharmony_ci rose->condition = 0x00; 1728c2ecf20Sopenharmony_ci rose->vs = 0; 1738c2ecf20Sopenharmony_ci rose->vr = 0; 1748c2ecf20Sopenharmony_ci rose->va = 0; 1758c2ecf20Sopenharmony_ci rose->vl = 0; 1768c2ecf20Sopenharmony_ci rose->state = ROSE_STATE_4; 1778c2ecf20Sopenharmony_ci rose_start_t2timer(sk); 1788c2ecf20Sopenharmony_ci rose_stop_idletimer(sk); 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) > 1828c2ecf20Sopenharmony_ci (sk->sk_rcvbuf >> 1)) 1838c2ecf20Sopenharmony_ci rose->condition |= ROSE_COND_OWN_RX_BUSY; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * If the window is full, ack the frame, else start the 1878c2ecf20Sopenharmony_ci * acknowledge hold back timer. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) { 1908c2ecf20Sopenharmony_ci rose->condition &= ~ROSE_COND_ACK_PENDING; 1918c2ecf20Sopenharmony_ci rose_stop_timer(sk); 1928c2ecf20Sopenharmony_ci rose_enquiry_response(sk); 1938c2ecf20Sopenharmony_ci } else { 1948c2ecf20Sopenharmony_ci rose->condition |= ROSE_COND_ACK_PENDING; 1958c2ecf20Sopenharmony_ci rose_start_hbtimer(sk); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci default: 2008c2ecf20Sopenharmony_ci printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype); 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return queued; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * State machine for state 4, Awaiting Reset Confirmation State. 2098c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file rose_timer.c 2108c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_rose.c. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_cistatic int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci switch (frametype) { 2178c2ecf20Sopenharmony_ci case ROSE_RESET_REQUEST: 2188c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_RESET_CONFIRMATION); 2198c2ecf20Sopenharmony_ci fallthrough; 2208c2ecf20Sopenharmony_ci case ROSE_RESET_CONFIRMATION: 2218c2ecf20Sopenharmony_ci rose_stop_timer(sk); 2228c2ecf20Sopenharmony_ci rose_start_idletimer(sk); 2238c2ecf20Sopenharmony_ci rose->condition = 0x00; 2248c2ecf20Sopenharmony_ci rose->va = 0; 2258c2ecf20Sopenharmony_ci rose->vr = 0; 2268c2ecf20Sopenharmony_ci rose->vs = 0; 2278c2ecf20Sopenharmony_ci rose->vl = 0; 2288c2ecf20Sopenharmony_ci rose->state = ROSE_STATE_3; 2298c2ecf20Sopenharmony_ci rose_requeue_frames(sk); 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci case ROSE_CLEAR_REQUEST: 2338c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); 2348c2ecf20Sopenharmony_ci rose_disconnect(sk, 0, skb->data[3], skb->data[4]); 2358c2ecf20Sopenharmony_ci rose->neighbour->use--; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci default: 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/* 2468c2ecf20Sopenharmony_ci * State machine for state 5, Awaiting Call Acceptance State. 2478c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file rose_timer.c 2488c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_rose.c. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_cistatic int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci if (frametype == ROSE_CLEAR_REQUEST) { 2538c2ecf20Sopenharmony_ci rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); 2548c2ecf20Sopenharmony_ci rose_disconnect(sk, 0, skb->data[3], skb->data[4]); 2558c2ecf20Sopenharmony_ci rose_sk(sk)->neighbour->use--; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* Higher level upcall for a LAPB frame */ 2628c2ecf20Sopenharmony_ciint rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct rose_sock *rose = rose_sk(sk); 2658c2ecf20Sopenharmony_ci int queued = 0, frametype, ns, nr, q, d, m; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (rose->state == ROSE_STATE_0) 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci switch (rose->state) { 2738c2ecf20Sopenharmony_ci case ROSE_STATE_1: 2748c2ecf20Sopenharmony_ci queued = rose_state1_machine(sk, skb, frametype); 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case ROSE_STATE_2: 2778c2ecf20Sopenharmony_ci queued = rose_state2_machine(sk, skb, frametype); 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case ROSE_STATE_3: 2808c2ecf20Sopenharmony_ci queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m); 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci case ROSE_STATE_4: 2838c2ecf20Sopenharmony_ci queued = rose_state4_machine(sk, skb, frametype); 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case ROSE_STATE_5: 2868c2ecf20Sopenharmony_ci queued = rose_state5_machine(sk, skb, frametype); 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci rose_kick(sk); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return queued; 2938c2ecf20Sopenharmony_ci} 294