/* * State machine for state 2, Awaiting Release State. * The handling of the timer(s) is in file lapb_timer.c */ static void lapb_state2_machine(struct lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { switch (frame->type) { case LAPB_SABM: case LAPB_SABME: lapb_dbg(1, "(%p) S2 RX {SABM,SABME}(%d)\n", lapb->dev, frame->pf); lapb_dbg(1, "(%p) S2 TX DM(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; case LAPB_DISC: lapb_dbg(1, "(%p) S2 RX DISC(%d)\n", lapb->dev, frame->pf); lapb_dbg(1, "(%p) S2 TX UA(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); break; case LAPB_UA: lapb_dbg(1, "(%p) S2 RX UA(%d)\n", lapb->dev, frame->pf); if (frame->pf) { lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev); lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb_disconnect_confirmation(lapb, LAPB_OK); } break; case LAPB_DM: lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf); if (frame->pf) { lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev); lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED); } break; case LAPB_I: case LAPB_REJ: case LAPB_RNR: case LAPB_RR: lapb_dbg(1, "(%p) S2 RX {I,REJ,RNR,RR}(%d)\n", lapb->dev, frame->pf); lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf); if (frame->pf) lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; } kfree_skb(skb); }
int lapb_disconnect_request(void *token) { lapb_cb *lapb; if ((lapb = lapb_tokentostruct(token)) == NULL) return LAPB_BADTOKEN; switch (lapb->state) { case LAPB_STATE_0: return LAPB_NOTCONNECTED; case LAPB_STATE_1: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->token); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); #endif lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); return LAPB_NOTCONNECTED; case LAPB_STATE_2: return LAPB_OK; } lapb_clear_queues(lapb); lapb->n2count = 0; lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_2; #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token); #endif return LAPB_OK; }
void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short nr) { if (lapb->vs == nr) { lapb_frames_acked(lapb, nr); lapb_stop_t1timer(lapb); lapb->n2count = 0; } else if (lapb->va != nr) { lapb_frames_acked(lapb, nr); lapb_start_t1timer(lapb); } }
void lapb_kick(lapb_cb *lapb) { struct sk_buff *skb, *skbn; unsigned short modulus, start, end; modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; start = (skb_peek(&lapb->ack_queue) == NULL) ? lapb->va : lapb->vs; end = (lapb->va + lapb->window) % modulus; if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) && start != end && skb_peek(&lapb->write_queue) != NULL) { lapb->vs = start; /* * Dequeue the frame and copy it. */ skb = skb_dequeue(&lapb->write_queue); do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { skb_queue_head(&lapb->write_queue, skb); break; } if (skb->sk != NULL) skb_set_owner_w(skbn, skb->sk); /* * Transmit the frame copy. */ lapb_send_iframe(lapb, skbn, LAPB_POLLOFF); lapb->vs = (lapb->vs + 1) % modulus; /* * Requeue the original data frame. */ skb_queue_tail(&lapb->ack_queue, skb); } while (lapb->vs != end && (skb = skb_dequeue(&lapb->write_queue)) != NULL); lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; if (!lapb_t1timer_running(lapb)) lapb_start_t1timer(lapb); } }
void lapb_establish_data_link(struct lapb_cb *lapb) { lapb->condition = 0x00; lapb->n2count = 0; if (lapb->mode & LAPB_EXTENDED) { lapb_dbg(1, "(%p) S%d TX SABME(1)\n", lapb->dev, lapb->state); lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); } else { lapb_dbg(1, "(%p) S%d TX SABM(1)\n", lapb->dev, lapb->state); lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); } lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); }
int lapb_register(void *token, struct lapb_register_struct *callbacks) { lapb_cb *lapb; if (lapb_tokentostruct(token) != NULL) return LAPB_BADTOKEN; if ((lapb = lapb_create_cb()) == NULL) return LAPB_NOMEM; lapb->token = token; lapb->callbacks = *callbacks; lapb_insert_cb(lapb); lapb_start_t1timer(lapb); return LAPB_OK; }
void lapb_establish_data_link(lapb_cb *lapb) { lapb->condition = 0x00; lapb->n2count = 0; if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n", lapb->token, lapb->state); #endif lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n", lapb->token, lapb->state); #endif lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); } lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); }
/* * State machine for state 3, Connected State. * The handling of the timer(s) is in file lapb_timer.c */ static void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { int queued = 0; int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; switch (frame->type) { case LAPB_SABM: lapb_dbg(1, "(%p) S3 RX SABM(%d)\n", lapb->dev, frame->pf); if (lapb->mode & LAPB_EXTENDED) { lapb_dbg(1, "(%p) S3 TX DM(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { lapb_dbg(1, "(%p) S3 TX UA(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_stop_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->condition = 0x00; lapb->n2count = 0; lapb->vs = 0; lapb->vr = 0; lapb->va = 0; lapb_requeue_frames(lapb); } break; case LAPB_SABME: lapb_dbg(1, "(%p) S3 RX SABME(%d)\n", lapb->dev, frame->pf); if (lapb->mode & LAPB_EXTENDED) { lapb_dbg(1, "(%p) S3 TX UA(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_stop_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->condition = 0x00; lapb->n2count = 0; lapb->vs = 0; lapb->vr = 0; lapb->va = 0; lapb_requeue_frames(lapb); } else { lapb_dbg(1, "(%p) S3 TX DM(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } break; case LAPB_DISC: lapb_dbg(1, "(%p) S3 RX DISC(%d)\n", lapb->dev, frame->pf); lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev); lapb_clear_queues(lapb); lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_0; lapb_disconnect_indication(lapb, LAPB_OK); break; case LAPB_DM: lapb_dbg(1, "(%p) S3 RX DM(%d)\n", lapb->dev, frame->pf); lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev); lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED); break; case LAPB_RNR: lapb_dbg(1, "(%p) S3 RX RNR(%d) R%d\n", lapb->dev, frame->pf, frame->nr); lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); if (lapb_validate_nr(lapb, frame->nr)) { lapb_check_iframes_acked(lapb, frame->nr); } else { lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_Z; lapb_transmit_frmr(lapb); lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; } break; case LAPB_RR: lapb_dbg(1, "(%p) S3 RX RR(%d) R%d\n", lapb->dev, frame->pf, frame->nr); lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); if (lapb_validate_nr(lapb, frame->nr)) { lapb_check_iframes_acked(lapb, frame->nr); } else { lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_Z; lapb_transmit_frmr(lapb); lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; } break; case LAPB_REJ: lapb_dbg(1, "(%p) S3 RX REJ(%d) R%d\n", lapb->dev, frame->pf, frame->nr); lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); if (lapb_validate_nr(lapb, frame->nr)) { lapb_frames_acked(lapb, frame->nr); lapb_stop_t1timer(lapb); lapb->n2count = 0; lapb_requeue_frames(lapb); } else { lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_Z; lapb_transmit_frmr(lapb); lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; } break; case LAPB_I: lapb_dbg(1, "(%p) S3 RX I(%d) S%d R%d\n", lapb->dev, frame->pf, frame->ns, frame->nr); if (!lapb_validate_nr(lapb, frame->nr)) { lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_Z; lapb_transmit_frmr(lapb); lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; break; } if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) lapb_frames_acked(lapb, frame->nr); else lapb_check_iframes_acked(lapb, frame->nr); if (frame->ns == lapb->vr) { int cn; cn = lapb_data_indication(lapb, skb); queued = 1; /* * If upper layer has dropped the frame, we * basically ignore any further protocol * processing. This will cause the peer * to re-transmit the frame later like * a frame lost on the wire. */ if (cn == NET_RX_DROP) { pr_debug("rx congestion\n"); break; } lapb->vr = (lapb->vr + 1) % modulus; lapb->condition &= ~LAPB_REJECT_CONDITION; if (frame->pf) lapb_enquiry_response(lapb); else { if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) { lapb->condition |= LAPB_ACK_PENDING_CONDITION; lapb_start_t2timer(lapb); } } } else { if (lapb->condition & LAPB_REJECT_CONDITION) { if (frame->pf) lapb_enquiry_response(lapb); } else { lapb_dbg(1, "(%p) S3 TX REJ(%d) R%d\n", lapb->dev, frame->pf, lapb->vr); lapb->condition |= LAPB_REJECT_CONDITION; lapb_send_control(lapb, LAPB_REJ, frame->pf, LAPB_RESPONSE); lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; } } break; case LAPB_FRMR: lapb_dbg(1, "(%p) S3 RX FRMR(%d) %5ph\n", lapb->dev, frame->pf, skb->data); lapb_establish_data_link(lapb); lapb_dbg(0, "(%p) S3 -> S1\n", lapb->dev); lapb_requeue_frames(lapb); lapb->state = LAPB_STATE_1; break; case LAPB_ILLEGAL: lapb_dbg(1, "(%p) S3 RX ILLEGAL(%d)\n", lapb->dev, frame->pf); lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_W; lapb_transmit_frmr(lapb); lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev); lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; break; } if (!queued) kfree_skb(skb); }
/* * State machine for state 1, Awaiting Connection State. * The handling of the timer(s) is in file lapb_timer.c. */ static void lapb_state1_machine(struct lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { switch (frame->type) { case LAPB_SABM: lapb_dbg(1, "(%p) S1 RX SABM(%d)\n", lapb->dev, frame->pf); if (lapb->mode & LAPB_EXTENDED) { lapb_dbg(1, "(%p) S1 TX DM(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { lapb_dbg(1, "(%p) S1 TX UA(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); } break; case LAPB_SABME: lapb_dbg(1, "(%p) S1 RX SABME(%d)\n", lapb->dev, frame->pf); if (lapb->mode & LAPB_EXTENDED) { lapb_dbg(1, "(%p) S1 TX UA(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); } else { lapb_dbg(1, "(%p) S1 TX DM(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } break; case LAPB_DISC: lapb_dbg(1, "(%p) S1 RX DISC(%d)\n", lapb->dev, frame->pf); lapb_dbg(1, "(%p) S1 TX DM(%d)\n", lapb->dev, frame->pf); lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; case LAPB_UA: lapb_dbg(1, "(%p) S1 RX UA(%d)\n", lapb->dev, frame->pf); if (frame->pf) { lapb_dbg(0, "(%p) S1 -> S3\n", lapb->dev); lapb_stop_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_3; lapb->condition = 0x00; lapb->n2count = 0; lapb->vs = 0; lapb->vr = 0; lapb->va = 0; lapb_connect_confirmation(lapb, LAPB_OK); } break; case LAPB_DM: lapb_dbg(1, "(%p) S1 RX DM(%d)\n", lapb->dev, frame->pf); if (frame->pf) { lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev); lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb_disconnect_indication(lapb, LAPB_REFUSED); } break; } kfree_skb(skb); }
static void lapb_t1timer_expiry(unsigned long param) { lapb_cb *lapb = (lapb_cb *)param; switch (lapb->state) { /* * If we are a DCE, keep going DM .. DM .. DM */ case LAPB_STATE_0: if (lapb->mode & LAPB_DCE) lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE); break; /* * Awaiting connection state, send SABM(E), up to N2 times. */ case LAPB_STATE_1: if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); #endif return; } else { lapb->n2count++; if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX SABME(1)\n", lapb->token); #endif lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX SABM(1)\n", lapb->token); #endif lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); } } break; /* * Awaiting disconnection state, send DISC, up to N2 times. */ case LAPB_STATE_2: if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); #endif return; } else { lapb->n2count++; #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 TX DISC(1)\n", lapb->token); #endif lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); } break; /* * Data transfer state, restransmit I frames, up to N2 times. */ case LAPB_STATE_3: if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_stop_t2timer(lapb); lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); #endif return; } else { lapb->n2count++; lapb_requeue_frames(lapb); } break; /* * Frame reject state, restransmit FRMR frames, up to N2 times. */ case LAPB_STATE_4: if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token); #endif return; } else { lapb->n2count++; lapb_transmit_frmr(lapb); } break; } lapb_start_t1timer(lapb); }
static void lapb_t1timer_expiry(unsigned long param) { struct lapb_cb *lapb = (struct lapb_cb *)param; switch (lapb->state) { case LAPB_STATE_0: if (lapb->mode & LAPB_DCE) lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE); break; case LAPB_STATE_1: if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->dev); #endif return; } else { lapb->n2count++; if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX SABME(1)\n", lapb->dev); #endif lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX SABM(1)\n", lapb->dev); #endif lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); } } break; case LAPB_STATE_2: if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->dev); #endif return; } else { lapb->n2count++; #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 TX DISC(1)\n", lapb->dev); #endif lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); } break; case LAPB_STATE_3: if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_stop_t2timer(lapb); lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->dev); #endif return; } else { lapb->n2count++; lapb_requeue_frames(lapb); } break; case LAPB_STATE_4: if (lapb->n2count == lapb->n2) { lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->dev); #endif return; } else { lapb->n2count++; lapb_transmit_frmr(lapb); } break; } lapb_start_t1timer(lapb); }
static void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { int queued = 0; int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; switch (frame->type) { case LAPB_SABM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n", lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_stop_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->condition = 0x00; lapb->n2count = 0; lapb->vs = 0; lapb->vr = 0; lapb->va = 0; lapb_requeue_frames(lapb); } break; case LAPB_SABME: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n", lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_stop_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->condition = 0x00; lapb->n2count = 0; lapb->vs = 0; lapb->vr = 0; lapb->va = 0; lapb_requeue_frames(lapb); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } break; case LAPB_DISC: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n", lapb->dev, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->dev); #endif lapb_clear_queues(lapb); lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_0; lapb_disconnect_indication(lapb, LAPB_OK); break; case LAPB_DM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n", lapb->dev, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->dev); #endif lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED); break; case LAPB_RNR: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n", lapb->dev, frame->pf, frame->nr); #endif lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); if (lapb_validate_nr(lapb, frame->nr)) { lapb_check_iframes_acked(lapb, frame->nr); } else { lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_Z; lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; } break; case LAPB_RR: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n", lapb->dev, frame->pf, frame->nr); #endif lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); if (lapb_validate_nr(lapb, frame->nr)) { lapb_check_iframes_acked(lapb, frame->nr); } else { lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_Z; lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; } break; case LAPB_REJ: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n", lapb->dev, frame->pf, frame->nr); #endif lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); if (lapb_validate_nr(lapb, frame->nr)) { lapb_frames_acked(lapb, frame->nr); lapb_stop_t1timer(lapb); lapb->n2count = 0; lapb_requeue_frames(lapb); } else { lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_Z; lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; } break; case LAPB_I: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n", lapb->dev, frame->pf, frame->ns, frame->nr); #endif if (!lapb_validate_nr(lapb, frame->nr)) { lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_Z; lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; break; } if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) lapb_frames_acked(lapb, frame->nr); else lapb_check_iframes_acked(lapb, frame->nr); if (frame->ns == lapb->vr) { int cn; cn = lapb_data_indication(lapb, skb); queued = 1; /* */ if (cn == NET_RX_DROP) { printk(KERN_DEBUG "LAPB: rx congestion\n"); break; } lapb->vr = (lapb->vr + 1) % modulus; lapb->condition &= ~LAPB_REJECT_CONDITION; if (frame->pf) lapb_enquiry_response(lapb); else { if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) { lapb->condition |= LAPB_ACK_PENDING_CONDITION; lapb_start_t2timer(lapb); } } } else { if (lapb->condition & LAPB_REJECT_CONDITION) { if (frame->pf) lapb_enquiry_response(lapb); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX REJ(%d) R%d\n", lapb->dev, frame->pf, lapb->vr); #endif lapb->condition |= LAPB_REJECT_CONDITION; lapb_send_control(lapb, LAPB_REJ, frame->pf, LAPB_RESPONSE); lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; } } break; case LAPB_FRMR: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X " "%02X %02X %02X %02X\n", lapb->dev, frame->pf, skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4]); #endif lapb_establish_data_link(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->dev); #endif lapb_requeue_frames(lapb); lapb->state = LAPB_STATE_1; break; case LAPB_ILLEGAL: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n", lapb->dev, frame->pf); #endif lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_W; lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_4; lapb->n2count = 0; break; } if (!queued) kfree_skb(skb); }
/* * State machine for state 2, Awaiting Release State. * The handling of the timer(s) is in file lapb_timer.c */ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { switch (frame->type) { case LAPB_SABM: case LAPB_SABME: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n", lapb->token, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; case LAPB_DISC: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", lapb->token, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); break; case LAPB_UA: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n", lapb->token, frame->pf); #endif if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); #endif lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb_disconnect_confirmation(lapb, LAPB_OK); } break; case LAPB_DM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf); #endif if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); #endif lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED); } break; case LAPB_I: case LAPB_REJ: case LAPB_RNR: case LAPB_RR: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf); #endif if (frame->pf) lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; default: break; } kfree_skb(skb); }
/* * State machine for state 1, Awaiting Connection State. * The handling of the timer(s) is in file lapb_timer.c. */ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { switch (frame->type) { case LAPB_SABM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n", lapb->token, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); } break; case LAPB_SABME: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n", lapb->token, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } break; case LAPB_DISC: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; case LAPB_UA: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n", lapb->token, frame->pf); #endif if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n", lapb->token); #endif lapb_stop_t1timer(lapb); lapb_stop_t2timer(lapb); lapb->state = LAPB_STATE_3; lapb->condition = 0x00; lapb->n2count = 0; lapb->vs = 0; lapb->vr = 0; lapb->va = 0; lapb_connect_confirmation(lapb, LAPB_OK); } break; case LAPB_DM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n", lapb->token, frame->pf); #endif if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); #endif lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); lapb_disconnect_indication(lapb, LAPB_REFUSED); } break; default: break; } kfree_skb(skb); }