18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * X.25 Packet Layer release 002 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This is ALPHA test software. This code may break your machine, 68c2ecf20Sopenharmony_ci * randomly fail to work with new releases, misbehave and/or generally 78c2ecf20Sopenharmony_ci * screw up. It might even work. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This code REQUIRES 2.1.15 or higher 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * History 128c2ecf20Sopenharmony_ci * X.25 001 Jonathan Naylor Started coding. 138c2ecf20Sopenharmony_ci * X.25 002 Jonathan Naylor Centralised disconnection code. 148c2ecf20Sopenharmony_ci * New timer architecture. 158c2ecf20Sopenharmony_ci * 2000-03-20 Daniela Squassoni Disabling/enabling of facilities 168c2ecf20Sopenharmony_ci * negotiation. 178c2ecf20Sopenharmony_ci * 2000-11-10 Henner Eisen Check and reset for out-of-sequence 188c2ecf20Sopenharmony_ci * i-frames. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "X25: " fmt 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/errno.h> 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/string.h> 278c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 288c2ecf20Sopenharmony_ci#include <net/sock.h> 298c2ecf20Sopenharmony_ci#include <net/tcp_states.h> 308c2ecf20Sopenharmony_ci#include <net/x25.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct sk_buff *skbo, *skbn = skb; 358c2ecf20Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci if (more) { 388c2ecf20Sopenharmony_ci x25->fraglen += skb->len; 398c2ecf20Sopenharmony_ci skb_queue_tail(&x25->fragment_queue, skb); 408c2ecf20Sopenharmony_ci skb_set_owner_r(skb, sk); 418c2ecf20Sopenharmony_ci return 0; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (!more && x25->fraglen > 0) { /* End of fragment */ 458c2ecf20Sopenharmony_ci int len = x25->fraglen + skb->len; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){ 488c2ecf20Sopenharmony_ci kfree_skb(skb); 498c2ecf20Sopenharmony_ci return 1; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci skb_queue_tail(&x25->fragment_queue, skb); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci skb_reset_transport_header(skbn); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci skbo = skb_dequeue(&x25->fragment_queue); 578c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skbo, skb_put(skbn, skbo->len), 588c2ecf20Sopenharmony_ci skbo->len); 598c2ecf20Sopenharmony_ci kfree_skb(skbo); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci while ((skbo = 628c2ecf20Sopenharmony_ci skb_dequeue(&x25->fragment_queue)) != NULL) { 638c2ecf20Sopenharmony_ci skb_pull(skbo, (x25->neighbour->extended) ? 648c2ecf20Sopenharmony_ci X25_EXT_MIN_LEN : X25_STD_MIN_LEN); 658c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skbo, 668c2ecf20Sopenharmony_ci skb_put(skbn, skbo->len), 678c2ecf20Sopenharmony_ci skbo->len); 688c2ecf20Sopenharmony_ci kfree_skb(skbo); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci x25->fraglen = 0; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci skb_set_owner_r(skbn, sk); 758c2ecf20Sopenharmony_ci skb_queue_tail(&sk->sk_receive_queue, skbn); 768c2ecf20Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 778c2ecf20Sopenharmony_ci sk->sk_data_ready(sk); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * State machine for state 1, Awaiting Call Accepted State. 848c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c. 858c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct x25_address source_addr, dest_addr; 908c2ecf20Sopenharmony_ci int len; 918c2ecf20Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci switch (frametype) { 948c2ecf20Sopenharmony_ci case X25_CALL_ACCEPTED: { 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci x25_stop_timer(sk); 978c2ecf20Sopenharmony_ci x25->condition = 0x00; 988c2ecf20Sopenharmony_ci x25->vs = 0; 998c2ecf20Sopenharmony_ci x25->va = 0; 1008c2ecf20Sopenharmony_ci x25->vr = 0; 1018c2ecf20Sopenharmony_ci x25->vl = 0; 1028c2ecf20Sopenharmony_ci x25->state = X25_STATE_3; 1038c2ecf20Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * Parse the data in the frame. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) 1088c2ecf20Sopenharmony_ci goto out_clear; 1098c2ecf20Sopenharmony_ci skb_pull(skb, X25_STD_MIN_LEN); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci len = x25_parse_address_block(skb, &source_addr, 1128c2ecf20Sopenharmony_ci &dest_addr); 1138c2ecf20Sopenharmony_ci if (len > 0) 1148c2ecf20Sopenharmony_ci skb_pull(skb, len); 1158c2ecf20Sopenharmony_ci else if (len < 0) 1168c2ecf20Sopenharmony_ci goto out_clear; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci len = x25_parse_facilities(skb, &x25->facilities, 1198c2ecf20Sopenharmony_ci &x25->dte_facilities, 1208c2ecf20Sopenharmony_ci &x25->vc_facil_mask); 1218c2ecf20Sopenharmony_ci if (len > 0) 1228c2ecf20Sopenharmony_ci skb_pull(skb, len); 1238c2ecf20Sopenharmony_ci else if (len < 0) 1248c2ecf20Sopenharmony_ci goto out_clear; 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * Copy any Call User Data. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci if (skb->len > 0) { 1298c2ecf20Sopenharmony_ci if (skb->len > X25_MAX_CUD_LEN) 1308c2ecf20Sopenharmony_ci goto out_clear; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci skb_copy_bits(skb, 0, x25->calluserdata.cuddata, 1338c2ecf20Sopenharmony_ci skb->len); 1348c2ecf20Sopenharmony_ci x25->calluserdata.cudlength = skb->len; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 1378c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci case X25_CALL_REQUEST: 1418c2ecf20Sopenharmony_ci /* call collision */ 1428c2ecf20Sopenharmony_ci x25->causediag.cause = 0x01; 1438c2ecf20Sopenharmony_ci x25->causediag.diagnostic = 0x48; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 1468c2ecf20Sopenharmony_ci x25_disconnect(sk, EISCONN, 0x01, 0x48); 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci case X25_CLEAR_REQUEST: 1508c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 1518c2ecf20Sopenharmony_ci goto out_clear; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 1548c2ecf20Sopenharmony_ci x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ciout_clear: 1648c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 1658c2ecf20Sopenharmony_ci x25->state = X25_STATE_2; 1668c2ecf20Sopenharmony_ci x25_start_t23timer(sk); 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* 1718c2ecf20Sopenharmony_ci * State machine for state 2, Awaiting Clear Confirmation State. 1728c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c 1738c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_cistatic int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci switch (frametype) { 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci case X25_CLEAR_REQUEST: 1808c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 1818c2ecf20Sopenharmony_ci goto out_clear; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 1848c2ecf20Sopenharmony_ci x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci case X25_CLEAR_CONFIRMATION: 1888c2ecf20Sopenharmony_ci x25_disconnect(sk, 0, 0, 0); 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci default: 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ciout_clear: 1988c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 1998c2ecf20Sopenharmony_ci x25_start_t23timer(sk); 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/* 2048c2ecf20Sopenharmony_ci * State machine for state 3, Connected State. 2058c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c 2068c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_cistatic int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int queued = 0; 2118c2ecf20Sopenharmony_ci int modulus; 2128c2ecf20Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci switch (frametype) { 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci case X25_RESET_REQUEST: 2198c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_RESET_CONFIRMATION); 2208c2ecf20Sopenharmony_ci x25_stop_timer(sk); 2218c2ecf20Sopenharmony_ci x25->condition = 0x00; 2228c2ecf20Sopenharmony_ci x25->vs = 0; 2238c2ecf20Sopenharmony_ci x25->vr = 0; 2248c2ecf20Sopenharmony_ci x25->va = 0; 2258c2ecf20Sopenharmony_ci x25->vl = 0; 2268c2ecf20Sopenharmony_ci x25_requeue_frames(sk); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci case X25_CLEAR_REQUEST: 2308c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 2318c2ecf20Sopenharmony_ci goto out_clear; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 2348c2ecf20Sopenharmony_ci x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci case X25_RR: 2388c2ecf20Sopenharmony_ci case X25_RNR: 2398c2ecf20Sopenharmony_ci if (!x25_validate_nr(sk, nr)) { 2408c2ecf20Sopenharmony_ci x25_clear_queues(sk); 2418c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_RESET_REQUEST); 2428c2ecf20Sopenharmony_ci x25_start_t22timer(sk); 2438c2ecf20Sopenharmony_ci x25->condition = 0x00; 2448c2ecf20Sopenharmony_ci x25->vs = 0; 2458c2ecf20Sopenharmony_ci x25->vr = 0; 2468c2ecf20Sopenharmony_ci x25->va = 0; 2478c2ecf20Sopenharmony_ci x25->vl = 0; 2488c2ecf20Sopenharmony_ci x25->state = X25_STATE_4; 2498c2ecf20Sopenharmony_ci } else { 2508c2ecf20Sopenharmony_ci x25_frames_acked(sk, nr); 2518c2ecf20Sopenharmony_ci if (frametype == X25_RNR) { 2528c2ecf20Sopenharmony_ci x25->condition |= X25_COND_PEER_RX_BUSY; 2538c2ecf20Sopenharmony_ci } else { 2548c2ecf20Sopenharmony_ci x25->condition &= ~X25_COND_PEER_RX_BUSY; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci case X25_DATA: /* XXX */ 2608c2ecf20Sopenharmony_ci x25->condition &= ~X25_COND_PEER_RX_BUSY; 2618c2ecf20Sopenharmony_ci if ((ns != x25->vr) || !x25_validate_nr(sk, nr)) { 2628c2ecf20Sopenharmony_ci x25_clear_queues(sk); 2638c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_RESET_REQUEST); 2648c2ecf20Sopenharmony_ci x25_start_t22timer(sk); 2658c2ecf20Sopenharmony_ci x25->condition = 0x00; 2668c2ecf20Sopenharmony_ci x25->vs = 0; 2678c2ecf20Sopenharmony_ci x25->vr = 0; 2688c2ecf20Sopenharmony_ci x25->va = 0; 2698c2ecf20Sopenharmony_ci x25->vl = 0; 2708c2ecf20Sopenharmony_ci x25->state = X25_STATE_4; 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci x25_frames_acked(sk, nr); 2748c2ecf20Sopenharmony_ci if (ns == x25->vr) { 2758c2ecf20Sopenharmony_ci if (x25_queue_rx_frame(sk, skb, m) == 0) { 2768c2ecf20Sopenharmony_ci x25->vr = (x25->vr + 1) % modulus; 2778c2ecf20Sopenharmony_ci queued = 1; 2788c2ecf20Sopenharmony_ci } else { 2798c2ecf20Sopenharmony_ci /* Should never happen */ 2808c2ecf20Sopenharmony_ci x25_clear_queues(sk); 2818c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_RESET_REQUEST); 2828c2ecf20Sopenharmony_ci x25_start_t22timer(sk); 2838c2ecf20Sopenharmony_ci x25->condition = 0x00; 2848c2ecf20Sopenharmony_ci x25->vs = 0; 2858c2ecf20Sopenharmony_ci x25->vr = 0; 2868c2ecf20Sopenharmony_ci x25->va = 0; 2878c2ecf20Sopenharmony_ci x25->vl = 0; 2888c2ecf20Sopenharmony_ci x25->state = X25_STATE_4; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) > 2928c2ecf20Sopenharmony_ci (sk->sk_rcvbuf >> 1)) 2938c2ecf20Sopenharmony_ci x25->condition |= X25_COND_OWN_RX_BUSY; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci /* 2968c2ecf20Sopenharmony_ci * If the window is full Ack it immediately, else 2978c2ecf20Sopenharmony_ci * start the holdback timer. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci if (((x25->vl + x25->facilities.winsize_in) % modulus) == x25->vr) { 3008c2ecf20Sopenharmony_ci x25->condition &= ~X25_COND_ACK_PENDING; 3018c2ecf20Sopenharmony_ci x25_stop_timer(sk); 3028c2ecf20Sopenharmony_ci x25_enquiry_response(sk); 3038c2ecf20Sopenharmony_ci } else { 3048c2ecf20Sopenharmony_ci x25->condition |= X25_COND_ACK_PENDING; 3058c2ecf20Sopenharmony_ci x25_start_t2timer(sk); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci break; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci case X25_INTERRUPT_CONFIRMATION: 3108c2ecf20Sopenharmony_ci clear_bit(X25_INTERRUPT_FLAG, &x25->flags); 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci case X25_INTERRUPT: 3148c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_URGINLINE)) 3158c2ecf20Sopenharmony_ci queued = !sock_queue_rcv_skb(sk, skb); 3168c2ecf20Sopenharmony_ci else { 3178c2ecf20Sopenharmony_ci skb_set_owner_r(skb, sk); 3188c2ecf20Sopenharmony_ci skb_queue_tail(&x25->interrupt_in_queue, skb); 3198c2ecf20Sopenharmony_ci queued = 1; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci sk_send_sigurg(sk); 3228c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION); 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci default: 3268c2ecf20Sopenharmony_ci pr_warn("unknown %02X in state 3\n", frametype); 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return queued; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ciout_clear: 3338c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 3348c2ecf20Sopenharmony_ci x25->state = X25_STATE_2; 3358c2ecf20Sopenharmony_ci x25_start_t23timer(sk); 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* 3408c2ecf20Sopenharmony_ci * State machine for state 4, Awaiting Reset Confirmation State. 3418c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c 3428c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_cistatic int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci switch (frametype) { 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci case X25_RESET_REQUEST: 3518c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_RESET_CONFIRMATION); 3528c2ecf20Sopenharmony_ci fallthrough; 3538c2ecf20Sopenharmony_ci case X25_RESET_CONFIRMATION: { 3548c2ecf20Sopenharmony_ci x25_stop_timer(sk); 3558c2ecf20Sopenharmony_ci x25->condition = 0x00; 3568c2ecf20Sopenharmony_ci x25->va = 0; 3578c2ecf20Sopenharmony_ci x25->vr = 0; 3588c2ecf20Sopenharmony_ci x25->vs = 0; 3598c2ecf20Sopenharmony_ci x25->vl = 0; 3608c2ecf20Sopenharmony_ci x25->state = X25_STATE_3; 3618c2ecf20Sopenharmony_ci x25_requeue_frames(sk); 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci case X25_CLEAR_REQUEST: 3658c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 3668c2ecf20Sopenharmony_ci goto out_clear; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 3698c2ecf20Sopenharmony_ci x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci default: 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ciout_clear: 3798c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 3808c2ecf20Sopenharmony_ci x25->state = X25_STATE_2; 3818c2ecf20Sopenharmony_ci x25_start_t23timer(sk); 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci/* 3868c2ecf20Sopenharmony_ci * State machine for state 5, Call Accepted / Call Connected pending (X25_ACCPT_APPRV_FLAG). 3878c2ecf20Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c 3888c2ecf20Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_cistatic int x25_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci switch (frametype) { 3958c2ecf20Sopenharmony_ci case X25_CLEAR_REQUEST: 3968c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) { 3978c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 3988c2ecf20Sopenharmony_ci x25->state = X25_STATE_2; 3998c2ecf20Sopenharmony_ci x25_start_t23timer(sk); 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 4048c2ecf20Sopenharmony_ci x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci default: 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/* Higher level upcall for a LAPB frame */ 4158c2ecf20Sopenharmony_ciint x25_process_rx_frame(struct sock *sk, struct sk_buff *skb) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 4188c2ecf20Sopenharmony_ci int queued = 0, frametype, ns, nr, q, d, m; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (x25->state == X25_STATE_0) 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci switch (x25->state) { 4268c2ecf20Sopenharmony_ci case X25_STATE_1: 4278c2ecf20Sopenharmony_ci queued = x25_state1_machine(sk, skb, frametype); 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci case X25_STATE_2: 4308c2ecf20Sopenharmony_ci queued = x25_state2_machine(sk, skb, frametype); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case X25_STATE_3: 4338c2ecf20Sopenharmony_ci queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m); 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci case X25_STATE_4: 4368c2ecf20Sopenharmony_ci queued = x25_state4_machine(sk, skb, frametype); 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci case X25_STATE_5: 4398c2ecf20Sopenharmony_ci queued = x25_state5_machine(sk, skb, frametype); 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci x25_kick(sk); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return queued; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ciint x25_backlog_rcv(struct sock *sk, struct sk_buff *skb) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci int queued = x25_process_rx_frame(sk, skb); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (!queued) 4538c2ecf20Sopenharmony_ci kfree_skb(skb); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 457