/* * State machine for state 2, Awaiting Release State. * The handling of the timer(s) is in file ax25_std_timer.c * Handling of state 0 and connection release is in ax25.c. */ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { switch (frametype) { case AX25_SABM: case AX25_SABME: ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); break; case AX25_DISC: ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); ax25_disconnect(ax25, 0); break; case AX25_DM: case AX25_UA: if (pf) ax25_disconnect(ax25, 0); break; case AX25_I: case AX25_REJ: case AX25_RNR: case AX25_RR: if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); break; default: break; } return 0; }
/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC * within the poll of any connected channel. Remember * that we are not allowed to send anything unless we * get polled by the Master. * * Thus we'll have to do parts of our T1 handling in * ax25_enquiry_response(). */ void ax25_t1_timeout(ax25_cb *ax25) { switch (ax25->state) { case AX25_STATE_1: if (ax25->n2count == ax25->n2) { if (ax25->modulus == AX25_MODULUS) { ax25_disconnect(ax25, ETIMEDOUT); } else { ax25->modulus = AX25_MODULUS; ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); ax25->n2count = 0; ax25_send_control(ax25, AX25_SABM, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND); } } else { ax25->n2count++; if (ax25->modulus == AX25_MODULUS) ax25_send_control(ax25, AX25_SABM, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND); else ax25_send_control(ax25, AX25_SABME, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND); } break; case AX25_STATE_2: if (ax25->n2count == ax25->n2) { ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_disconnect(ax25, ETIMEDOUT); } else { ax25->n2count++; if (!ax25_dev_is_dama_slave(ax25->device)) ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); } break; case AX25_STATE_3: ax25->n2count = 1; if (!ax25->dama_slave) ax25_transmit_enquiry(ax25); ax25->state = AX25_STATE_4; break; case AX25_STATE_4: if (ax25->n2count == ax25->n2) { ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); ax25_disconnect(ax25, ETIMEDOUT); } else { ax25->n2count++; if (!ax25->dama_slave) ax25_transmit_enquiry(ax25); } break; } ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); ax25_set_timer(ax25); }
void ax25_std_t1timer_expiry(ax25_cb *ax25) { switch (ax25->state) { case AX25_STATE_1: if (ax25->n2count == ax25->n2) { if (ax25->modulus == AX25_MODULUS) { ax25_disconnect(ax25, ETIMEDOUT); return; } else { ax25->modulus = AX25_MODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; ax25->n2count = 0; ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); } } else { ax25->n2count++; if (ax25->modulus == AX25_MODULUS) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); else ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); } break; case AX25_STATE_2: if (ax25->n2count == ax25->n2) { ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_disconnect(ax25, ETIMEDOUT); return; } else { ax25->n2count++; ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); } break; case AX25_STATE_3: ax25->n2count = 1; ax25_std_transmit_enquiry(ax25); ax25->state = AX25_STATE_4; break; case AX25_STATE_4: if (ax25->n2count == ax25->n2) { ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); ax25_disconnect(ax25, ETIMEDOUT); return; } else { ax25->n2count++; ax25_std_transmit_enquiry(ax25); } break; } ax25_calculate_t1(ax25); ax25_start_t1timer(ax25); }
void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type) { struct sk_buff *skbn; unsigned char *ptr; int headroom; if (ax25->ax25_dev == NULL) { ax25_disconnect(ax25, ENETUNREACH); return; } headroom = ax25_addr_size(ax25->digipeat); if (skb_headroom(skb) < headroom) { if ((skbn = skb_realloc_headroom(skb, headroom)) == NULL) { printk(KERN_CRIT "AX.25: ax25_transmit_buffer - out of memory\n"); kfree_skb(skb); return; } if (skb->sk != NULL) skb_set_owner_w(skbn, skb->sk); kfree_skb(skb); skb = skbn; } ptr = skb_push(skb, headroom); ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); ax25_queue_xmit(skb, ax25->ax25_dev->dev); }
/* * State machine for state 1, Awaiting Connection State. * The handling of the timer(s) is in file ax25_timer.c. * Handling of state 0 and connection release is in ax25.c. */ static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type, int dama) { switch (frametype) { case AX25_SABM: ax25->modulus = AX25_MODULUS; ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); break; case AX25_SABME: ax25->modulus = AX25_EMODULUS; ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); break; case AX25_DISC: ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); break; case AX25_UA: if (pf || dama) { if (dama) ax25_dama_on(ax25); /* bke */ ax25_calculate_rtt(ax25); ax25->t1timer = 0; ax25->t3timer = ax25->t3; ax25->idletimer = ax25->idle; ax25->vs = 0; ax25->va = 0; ax25->vr = 0; ax25->state = AX25_STATE_3; ax25->n2count = 0; ax25->dama_slave = dama; /* bke */ if (ax25->sk != NULL) { ax25->sk->state = TCP_ESTABLISHED; /* For WAIT_SABM connections we will produce an accept ready socket here */ if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); } } break; case AX25_DM: if (pf) { if (ax25->modulus == AX25_MODULUS) { ax25_disconnect(ax25, ECONNREFUSED); } else { ax25->modulus = AX25_MODULUS; ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); } } break; default: if (dama && pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); break; } return 0; }
/* * State machine for state 1, Awaiting Connection State. * The handling of the timer(s) is in file ax25_std_timer.c. * Handling of state 0 and connection release is in ax25.c. */ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { switch (frametype) { case AX25_SABM: ax25->modulus = AX25_MODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); break; case AX25_SABME: ax25->modulus = AX25_EMODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); break; case AX25_DISC: ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); break; case AX25_UA: if (pf) { ax25_calculate_rtt(ax25); ax25_stop_t1timer(ax25); ax25_start_t3timer(ax25); ax25_start_idletimer(ax25); ax25->vs = 0; ax25->va = 0; ax25->vr = 0; ax25->state = AX25_STATE_3; ax25->n2count = 0; if (ax25->sk != NULL) { bh_lock_sock(ax25->sk); ax25->sk->sk_state = TCP_ESTABLISHED; /* For WAIT_SABM connections we will produce an accept ready socket here */ if (!sock_flag(ax25->sk, SOCK_DEAD)) ax25->sk->sk_state_change(ax25->sk); bh_unlock_sock(ax25->sk); } } break; case AX25_DM: if (pf) { if (ax25->modulus == AX25_MODULUS) { ax25_disconnect(ax25, ECONNREFUSED); } else { ax25->modulus = AX25_MODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; } } break; default: break; } return 0; }
/* * State machine for state 1, Awaiting Connection State. * The handling of the timer(s) is in file ax25_ds_timer.c. * Handling of state 0 and connection release is in ax25.c. */ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { switch (frametype) { case AX25_SABM: ax25->modulus = AX25_MODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); break; case AX25_SABME: ax25->modulus = AX25_EMODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); break; case AX25_DISC: ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); break; case AX25_UA: ax25_calculate_rtt(ax25); ax25_stop_t1timer(ax25); ax25_start_t3timer(ax25); ax25_start_idletimer(ax25); ax25->vs = 0; ax25->va = 0; ax25->vr = 0; ax25->state = AX25_STATE_3; ax25->n2count = 0; if (ax25->sk != NULL) { ax25->sk->state = TCP_ESTABLISHED; /* For WAIT_SABM connections we will produce an accept ready socket here */ if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); } ax25_dama_on(ax25); /* according to DK4EG´s spec we are required to * send a RR RESPONSE FINAL NR=0. Please mail * <*****@*****.**> if this causes problems * with the TheNetNode DAMA Master implementation. */ ax25_std_enquiry_response(ax25); break; case AX25_DM: if (pf) ax25_disconnect(ax25, ECONNREFUSED); break; default: if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); break; } return 0; }
/* * Kill all bound sockets on a dropped device. */ static void ax25_kill_by_device(struct device *dev) { ax25_dev *ax25_dev; ax25_cb *s; if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) return; for (s = ax25_list; s != NULL; s = s->next) { if (s->ax25_dev == ax25_dev) { s->ax25_dev = NULL; ax25_disconnect(s, ENETUNREACH); } } }
/* * State machine for state 3, Connected State. * The handling of the timer(s) is in file ax25_timer.c * Handling of state 0 and connection release is in ax25.c. */ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) { int queued = 0; switch (frametype) { case AX25_SABM: case AX25_SABME: if (frametype == AX25_SABM) { ax25->modulus = AX25_MODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; } else { ax25->modulus = AX25_EMODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; } ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); ax25_stop_t1timer(ax25); ax25_start_t3timer(ax25); ax25_start_idletimer(ax25); ax25->condition = 0x00; ax25->vs = 0; ax25->va = 0; ax25->vr = 0; ax25_requeue_frames(ax25); ax25_dama_on(ax25); break; case AX25_DISC: ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); ax25_dama_off(ax25); ax25_disconnect(ax25, 0); break; case AX25_DM: ax25_dama_off(ax25); ax25_disconnect(ax25, ECONNRESET); break; case AX25_RR: case AX25_RNR: if (frametype == AX25_RR) ax25->condition &= ~AX25_COND_PEER_RX_BUSY; else ax25->condition |= AX25_COND_PEER_RX_BUSY; if (ax25_validate_nr(ax25, nr)) { if (ax25_check_iframes_acked(ax25, nr)) ax25->n2count=0; if (type == AX25_COMMAND && pf) ax25_ds_enquiry_response(ax25); } else { ax25_ds_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; } break; case AX25_REJ: ax25->condition &= ~AX25_COND_PEER_RX_BUSY; if (ax25_validate_nr(ax25, nr)) { if (ax25->va != nr) ax25->n2count=0; ax25_frames_acked(ax25, nr); ax25_calculate_rtt(ax25); ax25_stop_t1timer(ax25); ax25_start_t3timer(ax25); ax25_requeue_frames(ax25); if (type == AX25_COMMAND && pf) ax25_ds_enquiry_response(ax25); } else { ax25_ds_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; } break; case AX25_I: if (!ax25_validate_nr(ax25, nr)) { ax25_ds_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; break; } if (ax25->condition & AX25_COND_PEER_RX_BUSY) { ax25_frames_acked(ax25, nr); ax25->n2count = 0; } else { if (ax25_check_iframes_acked(ax25, nr)) ax25->n2count = 0; } if (ax25->condition & AX25_COND_OWN_RX_BUSY) { if (pf) ax25_ds_enquiry_response(ax25); break; } if (ns == ax25->vr) { ax25->vr = (ax25->vr + 1) % ax25->modulus; queued = ax25_rx_iframe(ax25, skb); if (ax25->condition & AX25_COND_OWN_RX_BUSY) ax25->vr = ns; /* ax25->vr - 1 */ ax25->condition &= ~AX25_COND_REJECT; if (pf) { ax25_ds_enquiry_response(ax25); } else { if (!(ax25->condition & AX25_COND_ACK_PENDING)) { ax25->condition |= AX25_COND_ACK_PENDING; ax25_start_t2timer(ax25); } } } else { if (ax25->condition & AX25_COND_REJECT) { if (pf) ax25_ds_enquiry_response(ax25); } else { ax25->condition |= AX25_COND_REJECT; ax25_ds_enquiry_response(ax25); ax25->condition &= ~AX25_COND_ACK_PENDING; } } break; case AX25_FRMR: case AX25_ILLEGAL: ax25_ds_establish_data_link(ax25); ax25->state = AX25_STATE_1; break; default: break; } return queued; }
/* * State machine for state 1, Awaiting Connection State. * The handling of the timer(s) is in file ax25_ds_timer.c. * Handling of state 0 and connection release is in ax25.c. */ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { switch (frametype) { case AX25_SABM: ax25->modulus = AX25_MODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); break; case AX25_SABME: ax25->modulus = AX25_EMODULUS; ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); break; case AX25_DISC: ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); break; case AX25_UA: ax25_calculate_rtt(ax25); ax25_stop_t1timer(ax25); ax25_start_t3timer(ax25); ax25_start_idletimer(ax25); ax25->vs = 0; ax25->va = 0; ax25->vr = 0; ax25->state = AX25_STATE_3; ax25->n2count = 0; if (ax25->sk != NULL) { bh_lock_sock(ax25->sk); ax25->sk->sk_state = TCP_ESTABLISHED; /* * For WAIT_SABM connections we will produce an accept * ready socket here */ if (!sock_flag(ax25->sk, SOCK_DEAD)) ax25->sk->sk_state_change(ax25->sk); bh_unlock_sock(ax25->sk); } ax25_dama_on(ax25); /* according to DK4EG's spec we are required to * send a RR RESPONSE FINAL NR=0. */ ax25_std_enquiry_response(ax25); break; case AX25_DM: if (pf) ax25_disconnect(ax25, ECONNREFUSED); break; default: if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); break; } return 0; }
/* * AX.25 TIMER * * This routine is called every 100ms. Decrement timer by this * amount - if expired then process the event. */ static void ax25_timer(unsigned long param) { ax25_cb *ax25 = (ax25_cb *)param; switch (ax25->state) { case AX25_STATE_0: /* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */ if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { ax25_destroy_socket(ax25); return; } break; case AX25_STATE_3: case AX25_STATE_4: /* * Check the state of the receive buffer. */ if (ax25->sk != NULL) { if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_ACK_PENDING; if (!ax25->dama_slave) ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); break; } } /* * Check for frames to transmit. */ if (!ax25->dama_slave) ax25_kick(ax25); break; default: break; } if (ax25->t2timer > 0 && --ax25->t2timer == 0) { if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) { if (ax25->condition & AX25_COND_ACK_PENDING) { ax25->condition &= ~AX25_COND_ACK_PENDING; if (!ax25->dama_slave) ax25_timeout_response(ax25); } } } if (ax25->t3timer > 0 && --ax25->t3timer == 0) { /* dl1bke 960114: T3 expires and we are in DAMA mode: */ /* send a DISC and abort the connection */ if (ax25->dama_slave) { ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_disconnect(ax25, ETIMEDOUT); ax25_set_timer(ax25); return; } if (ax25->state == AX25_STATE_3) { ax25->n2count = 0; ax25_transmit_enquiry(ax25); ax25->state = AX25_STATE_4; } ax25->t3timer = ax25->t3; } if (ax25->idletimer > 0 && --ax25->idletimer == 0) { /* dl1bke 960228: close the connection when IDLE expires */ /* similar to DAMA T3 timeout but with */ /* a "clean" disconnect of the connection */ ax25_clear_queues(ax25); ax25->n2count = 0; if (!ax25->dama_slave) { ax25->t3timer = 0; ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); } else { ax25->t3timer = ax25->t3; } /* state 1 or 2 should not happen, but... */ if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2) ax25->state = AX25_STATE_0; else ax25->state = AX25_STATE_2; ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); ax25->t2timer = 0; if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; } } /* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */ /* nevertheless we have to re-enqueue the timer struct... */ if (ax25->t1timer == 0 || --ax25->t1timer > 0) { ax25_set_timer(ax25); return; } if (!ax25_dev_is_dama_slave(ax25->device)) { if (ax25->dama_slave) ax25->dama_slave = 0; ax25_t1_timeout(ax25); } }