void ax25_std_nr_error_recovery(ax25_cb *ax25) { ax25_std_establish_data_link(ax25); }
ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev) { ax25_dev *ax25_dev; ax25_cb *ax25; /* * Take the default packet length for the device if zero is * specified. */ if (paclen == 0) { if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) return NULL; paclen = ax25_dev->values[AX25_VALUES_PACLEN]; } /* * Look for an existing connection. */ if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) { ax25_output(ax25, paclen, skb); return ax25; /* It already existed */ } if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) return NULL; if ((ax25 = ax25_create_cb()) == NULL) return NULL; ax25_fillin_cb(ax25, ax25_dev); ax25->source_addr = *src; ax25->dest_addr = *dest; if (digi != NULL) { ax25->digipeat = kmemdup(digi, sizeof(*digi), GFP_ATOMIC); if (ax25->digipeat == NULL) { ax25_cb_put(ax25); return NULL; } } switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_DUPLEX: ax25_std_establish_data_link(ax25); break; #ifdef CONFIG_AX25_DAMA_SLAVE case AX25_PROTO_DAMA_SLAVE: if (ax25_dev->dama.slave) ax25_ds_establish_data_link(ax25); else ax25_std_establish_data_link(ax25); break; #endif } /* * There is one ref for the state machine; a caller needs * one more to put it back, just like with the existing one. */ ax25_cb_hold(ax25); ax25_cb_add(ax25); ax25->state = AX25_STATE_1; ax25_start_heartbeat(ax25); ax25_output(ax25, paclen, skb); return ax25; /* We had to create it */ }
/* * State machine for state 4, Timer Recovery 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_state4_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_stop_t2timer(ax25); ax25_start_t3timer(ax25); ax25_start_idletimer(ax25); ax25->condition = 0x00; ax25->vs = 0; ax25->va = 0; ax25->vr = 0; ax25->state = AX25_STATE_3; ax25->n2count = 0; ax25_requeue_frames(ax25); break; case AX25_DISC: ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); ax25_disconnect(ax25, 0); break; case AX25_DM: 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 (type == AX25_RESPONSE && pf) { ax25_stop_t1timer(ax25); ax25->n2count = 0; if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); if (ax25->vs == ax25->va) { ax25_start_t3timer(ax25); ax25->state = AX25_STATE_3; } else { ax25_requeue_frames(ax25); } } else { ax25_std_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; } break; } if (type == AX25_COMMAND && pf) ax25_std_enquiry_response(ax25); if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); } else { ax25_std_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; } break; case AX25_REJ: ax25->condition &= ~AX25_COND_PEER_RX_BUSY; if (pf && type == AX25_RESPONSE) { ax25_stop_t1timer(ax25); ax25->n2count = 0; if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); if (ax25->vs == ax25->va) { ax25_start_t3timer(ax25); ax25->state = AX25_STATE_3; } else { ax25_requeue_frames(ax25); } } else { ax25_std_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; } break; } if (type == AX25_COMMAND && pf) ax25_std_enquiry_response(ax25); if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); ax25_requeue_frames(ax25); } else { ax25_std_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; } break; case AX25_I: if (!ax25_validate_nr(ax25, nr)) { ax25_std_nr_error_recovery(ax25); ax25->state = AX25_STATE_1; break; } ax25_frames_acked(ax25, nr); if (ax25->condition & AX25_COND_OWN_RX_BUSY) { if (pf) ax25_std_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_std_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_std_enquiry_response(ax25); } else { ax25->condition |= AX25_COND_REJECT; ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); ax25->condition &= ~AX25_COND_ACK_PENDING; } } break; case AX25_FRMR: case AX25_ILLEGAL: ax25_std_establish_data_link(ax25); ax25->state = AX25_STATE_1; break; default: break; } return queued; }