162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * X.25 Packet Layer release 002 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This is ALPHA test software. This code may break your machine, 662306a36Sopenharmony_ci * randomly fail to work with new releases, misbehave and/or generally 762306a36Sopenharmony_ci * screw up. It might even work. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This code REQUIRES 2.1.15 or higher 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * History 1262306a36Sopenharmony_ci * X.25 001 Jonathan Naylor Started coding. 1362306a36Sopenharmony_ci * X.25 002 Jonathan Naylor Centralised disconnection code. 1462306a36Sopenharmony_ci * New timer architecture. 1562306a36Sopenharmony_ci * 2000-03-20 Daniela Squassoni Disabling/enabling of facilities 1662306a36Sopenharmony_ci * negotiation. 1762306a36Sopenharmony_ci * 2000-11-10 Henner Eisen Check and reset for out-of-sequence 1862306a36Sopenharmony_ci * i-frames. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define pr_fmt(fmt) "X25: " fmt 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/errno.h> 2562306a36Sopenharmony_ci#include <linux/kernel.h> 2662306a36Sopenharmony_ci#include <linux/string.h> 2762306a36Sopenharmony_ci#include <linux/skbuff.h> 2862306a36Sopenharmony_ci#include <net/sock.h> 2962306a36Sopenharmony_ci#include <net/tcp_states.h> 3062306a36Sopenharmony_ci#include <net/x25.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct sk_buff *skbo, *skbn = skb; 3562306a36Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (more) { 3862306a36Sopenharmony_ci x25->fraglen += skb->len; 3962306a36Sopenharmony_ci skb_queue_tail(&x25->fragment_queue, skb); 4062306a36Sopenharmony_ci skb_set_owner_r(skb, sk); 4162306a36Sopenharmony_ci return 0; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (x25->fraglen > 0) { /* End of fragment */ 4562306a36Sopenharmony_ci int len = x25->fraglen + skb->len; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){ 4862306a36Sopenharmony_ci kfree_skb(skb); 4962306a36Sopenharmony_ci return 1; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci skb_queue_tail(&x25->fragment_queue, skb); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci skb_reset_transport_header(skbn); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci skbo = skb_dequeue(&x25->fragment_queue); 5762306a36Sopenharmony_ci skb_copy_from_linear_data(skbo, skb_put(skbn, skbo->len), 5862306a36Sopenharmony_ci skbo->len); 5962306a36Sopenharmony_ci kfree_skb(skbo); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci while ((skbo = 6262306a36Sopenharmony_ci skb_dequeue(&x25->fragment_queue)) != NULL) { 6362306a36Sopenharmony_ci skb_pull(skbo, (x25->neighbour->extended) ? 6462306a36Sopenharmony_ci X25_EXT_MIN_LEN : X25_STD_MIN_LEN); 6562306a36Sopenharmony_ci skb_copy_from_linear_data(skbo, 6662306a36Sopenharmony_ci skb_put(skbn, skbo->len), 6762306a36Sopenharmony_ci skbo->len); 6862306a36Sopenharmony_ci kfree_skb(skbo); 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci x25->fraglen = 0; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci skb_set_owner_r(skbn, sk); 7562306a36Sopenharmony_ci skb_queue_tail(&sk->sk_receive_queue, skbn); 7662306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 7762306a36Sopenharmony_ci sk->sk_data_ready(sk); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * State machine for state 1, Awaiting Call Accepted State. 8462306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c. 8562306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cistatic int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct x25_address source_addr, dest_addr; 9062306a36Sopenharmony_ci int len; 9162306a36Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci switch (frametype) { 9462306a36Sopenharmony_ci case X25_CALL_ACCEPTED: { 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci x25_stop_timer(sk); 9762306a36Sopenharmony_ci x25->condition = 0x00; 9862306a36Sopenharmony_ci x25->vs = 0; 9962306a36Sopenharmony_ci x25->va = 0; 10062306a36Sopenharmony_ci x25->vr = 0; 10162306a36Sopenharmony_ci x25->vl = 0; 10262306a36Sopenharmony_ci x25->state = X25_STATE_3; 10362306a36Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 10462306a36Sopenharmony_ci /* 10562306a36Sopenharmony_ci * Parse the data in the frame. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) 10862306a36Sopenharmony_ci goto out_clear; 10962306a36Sopenharmony_ci skb_pull(skb, X25_STD_MIN_LEN); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci len = x25_parse_address_block(skb, &source_addr, 11262306a36Sopenharmony_ci &dest_addr); 11362306a36Sopenharmony_ci if (len > 0) 11462306a36Sopenharmony_ci skb_pull(skb, len); 11562306a36Sopenharmony_ci else if (len < 0) 11662306a36Sopenharmony_ci goto out_clear; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci len = x25_parse_facilities(skb, &x25->facilities, 11962306a36Sopenharmony_ci &x25->dte_facilities, 12062306a36Sopenharmony_ci &x25->vc_facil_mask); 12162306a36Sopenharmony_ci if (len > 0) 12262306a36Sopenharmony_ci skb_pull(skb, len); 12362306a36Sopenharmony_ci else if (len < 0) 12462306a36Sopenharmony_ci goto out_clear; 12562306a36Sopenharmony_ci /* 12662306a36Sopenharmony_ci * Copy any Call User Data. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci if (skb->len > 0) { 12962306a36Sopenharmony_ci if (skb->len > X25_MAX_CUD_LEN) 13062306a36Sopenharmony_ci goto out_clear; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci skb_copy_bits(skb, 0, x25->calluserdata.cuddata, 13362306a36Sopenharmony_ci skb->len); 13462306a36Sopenharmony_ci x25->calluserdata.cudlength = skb->len; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 13762306a36Sopenharmony_ci sk->sk_state_change(sk); 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci case X25_CALL_REQUEST: 14162306a36Sopenharmony_ci /* call collision */ 14262306a36Sopenharmony_ci x25->causediag.cause = 0x01; 14362306a36Sopenharmony_ci x25->causediag.diagnostic = 0x48; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 14662306a36Sopenharmony_ci x25_disconnect(sk, EISCONN, 0x01, 0x48); 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci case X25_CLEAR_REQUEST: 15062306a36Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 15162306a36Sopenharmony_ci goto out_clear; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 15462306a36Sopenharmony_ci x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci default: 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ciout_clear: 16462306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 16562306a36Sopenharmony_ci x25->state = X25_STATE_2; 16662306a36Sopenharmony_ci x25_start_t23timer(sk); 16762306a36Sopenharmony_ci return 0; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * State machine for state 2, Awaiting Clear Confirmation State. 17262306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c 17362306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_cistatic int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci switch (frametype) { 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci case X25_CLEAR_REQUEST: 18062306a36Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 18162306a36Sopenharmony_ci goto out_clear; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 18462306a36Sopenharmony_ci x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci case X25_CLEAR_CONFIRMATION: 18862306a36Sopenharmony_ci x25_disconnect(sk, 0, 0, 0); 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci default: 19262306a36Sopenharmony_ci break; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ciout_clear: 19862306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 19962306a36Sopenharmony_ci x25_start_t23timer(sk); 20062306a36Sopenharmony_ci return 0; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* 20462306a36Sopenharmony_ci * State machine for state 3, Connected State. 20562306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c 20662306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci int queued = 0; 21162306a36Sopenharmony_ci int modulus; 21262306a36Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci switch (frametype) { 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci case X25_RESET_REQUEST: 21962306a36Sopenharmony_ci x25_write_internal(sk, X25_RESET_CONFIRMATION); 22062306a36Sopenharmony_ci x25_stop_timer(sk); 22162306a36Sopenharmony_ci x25->condition = 0x00; 22262306a36Sopenharmony_ci x25->vs = 0; 22362306a36Sopenharmony_ci x25->vr = 0; 22462306a36Sopenharmony_ci x25->va = 0; 22562306a36Sopenharmony_ci x25->vl = 0; 22662306a36Sopenharmony_ci x25_requeue_frames(sk); 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci case X25_CLEAR_REQUEST: 23062306a36Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 23162306a36Sopenharmony_ci goto out_clear; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 23462306a36Sopenharmony_ci x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci case X25_RR: 23862306a36Sopenharmony_ci case X25_RNR: 23962306a36Sopenharmony_ci if (!x25_validate_nr(sk, nr)) { 24062306a36Sopenharmony_ci x25_clear_queues(sk); 24162306a36Sopenharmony_ci x25_write_internal(sk, X25_RESET_REQUEST); 24262306a36Sopenharmony_ci x25_start_t22timer(sk); 24362306a36Sopenharmony_ci x25->condition = 0x00; 24462306a36Sopenharmony_ci x25->vs = 0; 24562306a36Sopenharmony_ci x25->vr = 0; 24662306a36Sopenharmony_ci x25->va = 0; 24762306a36Sopenharmony_ci x25->vl = 0; 24862306a36Sopenharmony_ci x25->state = X25_STATE_4; 24962306a36Sopenharmony_ci } else { 25062306a36Sopenharmony_ci x25_frames_acked(sk, nr); 25162306a36Sopenharmony_ci if (frametype == X25_RNR) { 25262306a36Sopenharmony_ci x25->condition |= X25_COND_PEER_RX_BUSY; 25362306a36Sopenharmony_ci } else { 25462306a36Sopenharmony_ci x25->condition &= ~X25_COND_PEER_RX_BUSY; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci case X25_DATA: /* XXX */ 26062306a36Sopenharmony_ci x25->condition &= ~X25_COND_PEER_RX_BUSY; 26162306a36Sopenharmony_ci if ((ns != x25->vr) || !x25_validate_nr(sk, nr)) { 26262306a36Sopenharmony_ci x25_clear_queues(sk); 26362306a36Sopenharmony_ci x25_write_internal(sk, X25_RESET_REQUEST); 26462306a36Sopenharmony_ci x25_start_t22timer(sk); 26562306a36Sopenharmony_ci x25->condition = 0x00; 26662306a36Sopenharmony_ci x25->vs = 0; 26762306a36Sopenharmony_ci x25->vr = 0; 26862306a36Sopenharmony_ci x25->va = 0; 26962306a36Sopenharmony_ci x25->vl = 0; 27062306a36Sopenharmony_ci x25->state = X25_STATE_4; 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci x25_frames_acked(sk, nr); 27462306a36Sopenharmony_ci if (ns == x25->vr) { 27562306a36Sopenharmony_ci if (x25_queue_rx_frame(sk, skb, m) == 0) { 27662306a36Sopenharmony_ci x25->vr = (x25->vr + 1) % modulus; 27762306a36Sopenharmony_ci queued = 1; 27862306a36Sopenharmony_ci } else { 27962306a36Sopenharmony_ci /* Should never happen */ 28062306a36Sopenharmony_ci x25_clear_queues(sk); 28162306a36Sopenharmony_ci x25_write_internal(sk, X25_RESET_REQUEST); 28262306a36Sopenharmony_ci x25_start_t22timer(sk); 28362306a36Sopenharmony_ci x25->condition = 0x00; 28462306a36Sopenharmony_ci x25->vs = 0; 28562306a36Sopenharmony_ci x25->vr = 0; 28662306a36Sopenharmony_ci x25->va = 0; 28762306a36Sopenharmony_ci x25->vl = 0; 28862306a36Sopenharmony_ci x25->state = X25_STATE_4; 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) > 29262306a36Sopenharmony_ci (sk->sk_rcvbuf >> 1)) 29362306a36Sopenharmony_ci x25->condition |= X25_COND_OWN_RX_BUSY; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci /* 29662306a36Sopenharmony_ci * If the window is full Ack it immediately, else 29762306a36Sopenharmony_ci * start the holdback timer. 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_ci if (((x25->vl + x25->facilities.winsize_in) % modulus) == x25->vr) { 30062306a36Sopenharmony_ci x25->condition &= ~X25_COND_ACK_PENDING; 30162306a36Sopenharmony_ci x25_stop_timer(sk); 30262306a36Sopenharmony_ci x25_enquiry_response(sk); 30362306a36Sopenharmony_ci } else { 30462306a36Sopenharmony_ci x25->condition |= X25_COND_ACK_PENDING; 30562306a36Sopenharmony_ci x25_start_t2timer(sk); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci case X25_INTERRUPT_CONFIRMATION: 31062306a36Sopenharmony_ci clear_bit(X25_INTERRUPT_FLAG, &x25->flags); 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci case X25_INTERRUPT: 31462306a36Sopenharmony_ci if (sock_flag(sk, SOCK_URGINLINE)) 31562306a36Sopenharmony_ci queued = !sock_queue_rcv_skb(sk, skb); 31662306a36Sopenharmony_ci else { 31762306a36Sopenharmony_ci skb_set_owner_r(skb, sk); 31862306a36Sopenharmony_ci skb_queue_tail(&x25->interrupt_in_queue, skb); 31962306a36Sopenharmony_ci queued = 1; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci sk_send_sigurg(sk); 32262306a36Sopenharmony_ci x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION); 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci default: 32662306a36Sopenharmony_ci pr_warn("unknown %02X in state 3\n", frametype); 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return queued; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciout_clear: 33362306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 33462306a36Sopenharmony_ci x25->state = X25_STATE_2; 33562306a36Sopenharmony_ci x25_start_t23timer(sk); 33662306a36Sopenharmony_ci return 0; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/* 34062306a36Sopenharmony_ci * State machine for state 4, Awaiting Reset Confirmation State. 34162306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c 34262306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_cistatic int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci switch (frametype) { 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci case X25_RESET_REQUEST: 35162306a36Sopenharmony_ci x25_write_internal(sk, X25_RESET_CONFIRMATION); 35262306a36Sopenharmony_ci fallthrough; 35362306a36Sopenharmony_ci case X25_RESET_CONFIRMATION: { 35462306a36Sopenharmony_ci x25_stop_timer(sk); 35562306a36Sopenharmony_ci x25->condition = 0x00; 35662306a36Sopenharmony_ci x25->va = 0; 35762306a36Sopenharmony_ci x25->vr = 0; 35862306a36Sopenharmony_ci x25->vs = 0; 35962306a36Sopenharmony_ci x25->vl = 0; 36062306a36Sopenharmony_ci x25->state = X25_STATE_3; 36162306a36Sopenharmony_ci x25_requeue_frames(sk); 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci case X25_CLEAR_REQUEST: 36562306a36Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 36662306a36Sopenharmony_ci goto out_clear; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 36962306a36Sopenharmony_ci x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci default: 37362306a36Sopenharmony_ci break; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ciout_clear: 37962306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 38062306a36Sopenharmony_ci x25->state = X25_STATE_2; 38162306a36Sopenharmony_ci x25_start_t23timer(sk); 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/* 38662306a36Sopenharmony_ci * State machine for state 5, Call Accepted / Call Connected pending (X25_ACCPT_APPRV_FLAG). 38762306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c 38862306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_cistatic int x25_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci switch (frametype) { 39562306a36Sopenharmony_ci case X25_CLEAR_REQUEST: 39662306a36Sopenharmony_ci if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) { 39762306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_REQUEST); 39862306a36Sopenharmony_ci x25->state = X25_STATE_2; 39962306a36Sopenharmony_ci x25_start_t23timer(sk); 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 40462306a36Sopenharmony_ci x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci default: 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci/* Higher level upcall for a LAPB frame */ 41562306a36Sopenharmony_ciint x25_process_rx_frame(struct sock *sk, struct sk_buff *skb) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct x25_sock *x25 = x25_sk(sk); 41862306a36Sopenharmony_ci int queued = 0, frametype, ns, nr, q, d, m; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (x25->state == X25_STATE_0) 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci switch (x25->state) { 42662306a36Sopenharmony_ci case X25_STATE_1: 42762306a36Sopenharmony_ci queued = x25_state1_machine(sk, skb, frametype); 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci case X25_STATE_2: 43062306a36Sopenharmony_ci queued = x25_state2_machine(sk, skb, frametype); 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci case X25_STATE_3: 43362306a36Sopenharmony_ci queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m); 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci case X25_STATE_4: 43662306a36Sopenharmony_ci queued = x25_state4_machine(sk, skb, frametype); 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci case X25_STATE_5: 43962306a36Sopenharmony_ci queued = x25_state5_machine(sk, skb, frametype); 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci x25_kick(sk); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return queued; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ciint x25_backlog_rcv(struct sock *sk, struct sk_buff *skb) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci int queued = x25_process_rx_frame(sk, skb); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (!queued) 45362306a36Sopenharmony_ci kfree_skb(skb); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci} 457