/* * State machine for state 4, Awaiting Reset Confirmation State. * 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_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) { switch (frametype) { case X25_RESET_REQUEST: x25_write_internal(sk, X25_RESET_CONFIRMATION); case X25_RESET_CONFIRMATION: { struct x25_sock *x25 = x25_sk(sk); x25_stop_timer(sk); x25->condition = 0x00; x25->va = 0; x25->vr = 0; x25->vs = 0; x25->vl = 0; x25->state = X25_STATE_3; x25_requeue_frames(sk); break; } case X25_CLEAR_REQUEST: x25_write_internal(sk, X25_CLEAR_CONFIRMATION); x25_disconnect(sk, 0, skb->data[3], skb->data[4]); break; default: break; } return 0; }
void x25_kick(struct sock *sk) { struct sk_buff *skb, *skbn; unsigned short start, end; int modulus; struct x25_sock *x25 = x25_sk(sk); if (x25->state != X25_STATE_3) return; if (skb_peek(&x25->interrupt_out_queue) != NULL && !test_and_set_bit(X25_INTERRUPT_FLAG, &x25->flags)) { skb = skb_dequeue(&x25->interrupt_out_queue); x25_transmit_link(skb, x25->neighbour); } if (x25->condition & X25_COND_PEER_RX_BUSY) return; if (!skb_peek(&sk->sk_write_queue)) return; modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS; start = skb_peek(&x25->ack_queue) ? x25->vs : x25->va; end = (x25->va + x25->facilities.winsize_out) % modulus; if (start == end) return; x25->vs = start; skb = skb_dequeue(&sk->sk_write_queue); do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { skb_queue_head(&sk->sk_write_queue, skb); break; } skb_set_owner_w(skbn, sk); x25_send_iframe(sk, skbn); x25->vs = (x25->vs + 1) % modulus; skb_queue_tail(&x25->ack_queue, skb); } while (x25->vs != end && (skb = skb_dequeue(&sk->sk_write_queue)) != NULL); x25->vl = x25->vr; x25->condition &= ~X25_COND_ACK_PENDING; x25_stop_timer(sk); }
void x25_enquiry_response(struct sock *sk) { if (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY) x25_write_internal(sk, X25_RNR); else x25_write_internal(sk, X25_RR); sk->protinfo.x25->vl = sk->protinfo.x25->vr; sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING; x25_stop_timer(sk); }
void x25_enquiry_response(struct sock *sk) { struct x25_opt *x25 = x25_sk(sk); if (x25->condition & X25_COND_OWN_RX_BUSY) x25_write_internal(sk, X25_RNR); else x25_write_internal(sk, X25_RR); x25->vl = x25->vr; x25->condition &= ~X25_COND_ACK_PENDING; x25_stop_timer(sk); }
/* * State machine for state 1, Awaiting Call Accepted State. * 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_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) { struct x25_address source_addr, dest_addr; switch (frametype) { case X25_CALL_ACCEPTED: { struct x25_sock *x25 = x25_sk(sk); x25_stop_timer(sk); x25->condition = 0x00; x25->vs = 0; x25->va = 0; x25->vr = 0; x25->vl = 0; x25->state = X25_STATE_3; sk->sk_state = TCP_ESTABLISHED; /* * Parse the data in the frame. */ skb_pull(skb, X25_STD_MIN_LEN); skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); skb_pull(skb, x25_parse_facilities(skb, &x25->facilities, &x25->dte_facilities, &x25->vc_facil_mask)); /* * Copy any Call User Data. */ if (skb->len >= 0) { memcpy(x25->calluserdata.cuddata, skb->data, skb->len); x25->calluserdata.cudlength = skb->len; } if (!sock_flag(sk, SOCK_DEAD)) sk->sk_state_change(sk); break; } case X25_CLEAR_REQUEST: x25_write_internal(sk, X25_CLEAR_CONFIRMATION); x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); break; default: break; } return 0; }
/* * State machine for state 3, Connected State. * 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_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m) { int queued = 0; int modulus; struct x25_sock *x25 = x25_sk(sk); modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS; switch (frametype) { case X25_RESET_REQUEST: x25_write_internal(sk, X25_RESET_CONFIRMATION); x25_stop_timer(sk); x25->condition = 0x00; x25->vs = 0; x25->vr = 0; x25->va = 0; x25->vl = 0; x25_requeue_frames(sk); break; case X25_CLEAR_REQUEST: x25_write_internal(sk, X25_CLEAR_CONFIRMATION); x25_disconnect(sk, 0, skb->data[3], skb->data[4]); break; case X25_RR: case X25_RNR: if (!x25_validate_nr(sk, nr)) { x25_clear_queues(sk); x25_write_internal(sk, X25_RESET_REQUEST); x25_start_t22timer(sk); x25->condition = 0x00; x25->vs = 0; x25->vr = 0; x25->va = 0; x25->vl = 0; x25->state = X25_STATE_4; } else { x25_frames_acked(sk, nr); if (frametype == X25_RNR) { x25->condition |= X25_COND_PEER_RX_BUSY; } else { x25->condition &= ~X25_COND_PEER_RX_BUSY; } } break; case X25_DATA: /* XXX */ x25->condition &= ~X25_COND_PEER_RX_BUSY; if ((ns != x25->vr) || !x25_validate_nr(sk, nr)) { x25_clear_queues(sk); x25_write_internal(sk, X25_RESET_REQUEST); x25_start_t22timer(sk); x25->condition = 0x00; x25->vs = 0; x25->vr = 0; x25->va = 0; x25->vl = 0; x25->state = X25_STATE_4; break; } x25_frames_acked(sk, nr); if (ns == x25->vr) { if (x25_queue_rx_frame(sk, skb, m) == 0) { x25->vr = (x25->vr + 1) % modulus; queued = 1; } else { /* Should never happen */ x25_clear_queues(sk); x25_write_internal(sk, X25_RESET_REQUEST); x25_start_t22timer(sk); x25->condition = 0x00; x25->vs = 0; x25->vr = 0; x25->va = 0; x25->vl = 0; x25->state = X25_STATE_4; break; } if (atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf / 2)) x25->condition |= X25_COND_OWN_RX_BUSY; } /* * If the window is full Ack it immediately, else * start the holdback timer. */ if (((x25->vl + x25->facilities.winsize_in) % modulus) == x25->vr) { x25->condition &= ~X25_COND_ACK_PENDING; x25_stop_timer(sk); x25_enquiry_response(sk); } else { x25->condition |= X25_COND_ACK_PENDING; x25_start_t2timer(sk); } break; case X25_INTERRUPT_CONFIRMATION: x25->intflag = 0; break; case X25_INTERRUPT: if (sock_flag(sk, SOCK_URGINLINE)) queued = !sock_queue_rcv_skb(sk, skb); else { skb_set_owner_r(skb, sk); skb_queue_tail(&x25->interrupt_in_queue, skb); queued = 1; } sk_send_sigurg(sk); x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION); break; default: printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype); break; } return queued; }
void x25_kick(struct sock *sk) { struct sk_buff *skb, *skbn; unsigned short start, end; int modulus; struct x25_opt *x25 = x25_sk(sk); if (x25->state != X25_STATE_3) return; /* * Transmit interrupt data. */ if (!x25->intflag && skb_peek(&x25->interrupt_out_queue) != NULL) { x25->intflag = 1; skb = skb_dequeue(&x25->interrupt_out_queue); x25_transmit_link(skb, x25->neighbour); } if (x25->condition & X25_COND_PEER_RX_BUSY) return; if (!skb_peek(&sk->sk_write_queue)) return; modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS; start = skb_peek(&x25->ack_queue) ? x25->vs : x25->va; end = (x25->va + x25->facilities.winsize_out) % modulus; if (start == end) return; x25->vs = start; /* * Transmit data until either we're out of data to send or * the window is full. */ skb = skb_dequeue(&sk->sk_write_queue); do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { skb_queue_head(&sk->sk_write_queue, skb); break; } skb_set_owner_w(skbn, sk); /* * Transmit the frame copy. */ x25_send_iframe(sk, skbn); x25->vs = (x25->vs + 1) % modulus; /* * Requeue the original data frame. */ skb_queue_tail(&x25->ack_queue, skb); } while (x25->vs != end && (skb = skb_dequeue(&sk->sk_write_queue)) != NULL); x25->vl = x25->vr; x25->condition &= ~X25_COND_ACK_PENDING; x25_stop_timer(sk); }
int x25_set_params(struct x25_cs * x25, struct x25_params *params) { int res = X25_BADTOKEN; if (!x25 || !params) goto out; res = X25_INVALUE; struct x25_cs_internal * x25_int = x25_get_internal(x25); /* Check and correct timers params */ if (params->RestartTimerInterval < 10000) params->RestartTimerInterval = X25_DEFAULT_RESTART_TIMER; if (params->CallTimerInterval < 10000) params->CallTimerInterval = X25_DEFAULT_CALL_TIMER; if (params->ResetTimerInterval < 10000) params->ResetTimerInterval = X25_DEFAULT_RESET_TIMER; if (params->ClearTimerInterval < 10000) params->ClearTimerInterval = X25_DEFAULT_CLEAR_TIMER; if (params->AckTimerInterval < 10000) params->AckTimerInterval = X25_DEFAULT_ACK_TIMER; if (params->DataTimerInterval < 10000) params->DataTimerInterval = X25_DEFAULT_DATA_TIMER; if (params->RestartTimerInterval > 300000) params->RestartTimerInterval = X25_DEFAULT_RESTART_TIMER; if (params->CallTimerInterval > 300000) params->CallTimerInterval = X25_DEFAULT_CALL_TIMER; if (params->ResetTimerInterval > 300000) params->ResetTimerInterval = X25_DEFAULT_RESET_TIMER; if (params->ClearTimerInterval > 300000) params->ClearTimerInterval = X25_DEFAULT_CLEAR_TIMER; if (params->AckTimerInterval > 300000) params->AckTimerInterval = X25_DEFAULT_ACK_TIMER; if (params->DataTimerInterval > 300000) params->DataTimerInterval = X25_DEFAULT_DATA_TIMER; if ((params->RestartTimerNR < 1) || (params->RestartTimerNR > 10)) params->RestartTimerNR = 2; if ((params->CallTimerNR < 1) || (params->CallTimerNR > 10)) params->CallTimerNR = 2; if ((params->ResetTimerNR < 1) || (params->ResetTimerNR > 10)) params->ResetTimerNR = 2; if ((params->ClearTimerNR < 1) || (params->ClearTimerNR > 10)) params->ClearTimerNR = 2; if ((params->AckTimerNR < 1) || (params->AckTimerNR > 10)) params->AckTimerNR = 2; if ((params->DataTimerNR < 1) || (params->DataTimerNR > 10)) params->DataTimerNR = 2; /* Apply new values */ if (x25_int->RestartTimer.interval != params->RestartTimerInterval) { x25_stop_timer(x25, &x25_int->RestartTimer); x25->callbacks->del_timer(x25_int->RestartTimer.timer_ptr); x25_int->RestartTimer.interval = params->RestartTimerInterval; x25_int->RestartTimer.timer_ptr = x25->callbacks->add_timer(x25_int->RestartTimer.interval, x25, x25_timer_expiry); }; x25->RestartTimer_NR = params->RestartTimerNR; if (x25_int->CallTimer.interval != params->CallTimerInterval) { x25_stop_timer(x25, &x25_int->CallTimer); x25->callbacks->del_timer(x25_int->CallTimer.timer_ptr); x25_int->CallTimer.interval = params->CallTimerInterval; x25_int->CallTimer.timer_ptr = x25->callbacks->add_timer(x25_int->CallTimer.interval, x25, x25_timer_expiry); }; x25->CallTimer_NR = params->CallTimerNR; if (x25_int->ResetTimer.interval != params->ResetTimerInterval) { x25_stop_timer(x25, &x25_int->ResetTimer); x25->callbacks->del_timer(x25_int->ResetTimer.timer_ptr); x25_int->ResetTimer.interval = params->ResetTimerInterval; x25_int->ResetTimer.timer_ptr = x25->callbacks->add_timer(x25_int->ResetTimer.interval, x25, x25_timer_expiry); }; x25->ResetTimer_NR = params->ResetTimerNR; if (x25_int->ClearTimer.interval != params->ClearTimerInterval) { x25_stop_timer(x25, &x25_int->ClearTimer); x25->callbacks->del_timer(x25_int->ClearTimer.timer_ptr); x25_int->ClearTimer.interval = params->ClearTimerInterval; x25_int->ClearTimer.timer_ptr = x25->callbacks->add_timer(x25_int->ClearTimer.interval, x25, x25_timer_expiry); }; x25->ClearTimer_NR = params->ClearTimerNR; if (x25_int->AckTimer.interval != params->AckTimerInterval) { x25_stop_timer(x25, &x25_int->AckTimer); x25->callbacks->del_timer(x25_int->AckTimer.timer_ptr); x25_int->AckTimer.interval = params->AckTimerInterval; x25_int->AckTimer.timer_ptr = x25->callbacks->add_timer(x25_int->AckTimer.interval, x25, x25_timer_expiry); }; x25->AckTimer_NR = params->AckTimerNR; if (x25_int->DataTimer.interval != params->DataTimerInterval) { x25_stop_timer(x25, &x25_int->AckTimer); x25->callbacks->del_timer(x25_int->DataTimer.timer_ptr); x25_int->DataTimer.interval = params->DataTimerInterval; x25_int->DataTimer.timer_ptr = x25->callbacks->add_timer(x25_int->DataTimer.interval, x25, x25_timer_expiry); }; x25->DataTimer_NR = params->DataTimerNR; /* Check and correct facilities values */ if (x25_is_extended(x25)) { if ((params->WinsizeIn < 1) || (params->WinsizeIn > 127)) params->WinsizeIn = X25_DEFAULT_WINDOW_SIZE; if ((params->WinsizeOut < 1) || (params->WinsizeOut > 127)) params->WinsizeOut = X25_DEFAULT_WINDOW_SIZE; } else { if ((params->WinsizeIn < 1) || (params->WinsizeIn > 7)) params->WinsizeIn = X25_DEFAULT_WINDOW_SIZE; if ((params->WinsizeOut < 1) || (params->WinsizeOut > 7)) params->WinsizeOut = X25_DEFAULT_WINDOW_SIZE; }; if ((params->PacsizeIn < X25_PS16) || (params->PacsizeIn > X25_PS4096)) params->PacsizeIn = X25_DEFAULT_PACKET_SIZE; if ((params->PacsizeOut < X25_PS16) || (params->PacsizeOut > X25_PS4096)) params->PacsizeOut = X25_DEFAULT_PACKET_SIZE; /* Apply new facilites */ x25_int->facilities.winsize_in = params->WinsizeIn; x25_int->facilities.winsize_out = params->WinsizeOut; x25_int->facilities.pacsize_in = params->PacsizeIn; x25_int->facilities.pacsize_out = params->PacsizeOut; out: return res; }