net/x25: add new state X25_STATE_5
authorMartin Schiller <ms@dev.tdt.de>
Mon, 9 Dec 2019 07:21:34 +0000 (08:21 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 9 Dec 2019 18:28:43 +0000 (10:28 -0800)
This is needed, because if the flag X25_ACCPT_APPRV_FLAG is not set on a
socket (manual call confirmation) and the channel is cleared by remote
before the manual call confirmation was sent, this situation needs to
be handled.

Signed-off-by: Martin Schiller <ms@dev.tdt.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/x25.h
net/x25/af_x25.c
net/x25/x25_in.c

index ed1acc3044ace48ecd0db0dfe1b7ac3fce23c3fa..d7d6c2b4ffa7153b0caef7dd249ba93f5f39e414 100644 (file)
@@ -62,7 +62,8 @@ enum {
        X25_STATE_1,            /* Awaiting Call Accepted */
        X25_STATE_2,            /* Awaiting Clear Confirmation */
        X25_STATE_3,            /* Data Transfer */
-       X25_STATE_4             /* Awaiting Reset Confirmation */
+       X25_STATE_4,            /* Awaiting Reset Confirmation */
+       X25_STATE_5             /* Call Accepted / Call Connected pending */
 };
 
 enum {
index c34f7d0776046f2c15b668b66f020be8008ea731..2efe44a346443d6715b271437d3c0d8de52f1f3e 100644 (file)
@@ -659,6 +659,12 @@ static int x25_release(struct socket *sock)
                        sock_set_flag(sk, SOCK_DEAD);
                        sock_set_flag(sk, SOCK_DESTROY);
                        break;
+
+               case X25_STATE_5:
+                       x25_write_internal(sk, X25_CLEAR_REQUEST);
+                       x25_disconnect(sk, 0, 0, 0);
+                       __x25_destroy_socket(sk);
+                       goto out;
        }
 
        sock_orphan(sk);
@@ -1054,6 +1060,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        if (test_bit(X25_ACCPT_APPRV_FLAG, &makex25->flags)) {
                x25_write_internal(make, X25_CALL_ACCEPTED);
                makex25->state = X25_STATE_3;
+       } else {
+               makex25->state = X25_STATE_5;
        }
 
        /*
index f97c43344e95dd31fb5efa3fd7f83192ab7ad333..4d3bb46aaae0d9b0d5e4c17168b6886b48677d41 100644 (file)
@@ -382,6 +382,35 @@ out_clear:
        return 0;
 }
 
+/*
+ * State machine for state 5, Call Accepted / Call Connected pending (X25_ACCPT_APPRV_FLAG).
+ * The handling of the timer(s) is in file x25_timer.c
+ * Handling of state 0 and connection release is in af_x25.c.
+ */
+static int x25_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype)
+{
+       struct x25_sock *x25 = x25_sk(sk);
+
+       switch (frametype) {
+               case X25_CLEAR_REQUEST:
+                       if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) {
+                               x25_write_internal(sk, X25_CLEAR_REQUEST);
+                               x25->state = X25_STATE_2;
+                               x25_start_t23timer(sk);
+                               return 0;
+                       }
+
+                       x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
+                       x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
+                       break;
+
+               default:
+                       break;
+       }
+
+       return 0;
+}
+
 /* Higher level upcall for a LAPB frame */
 int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
@@ -406,6 +435,9 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
        case X25_STATE_4:
                queued = x25_state4_machine(sk, skb, frametype);
                break;
+       case X25_STATE_5:
+               queued = x25_state5_machine(sk, skb, frametype);
+               break;
        }
 
        x25_kick(sk);