📄 irlap_event.c
字号:
} return ret;}/* * Function irlap_state_nrm_s (event, skb, info) * * NRM_S (Normal Response Mode as Secondary) state, in this state we are * expecting to receive frames from the primary station * */static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info){ int ns_status; int nr_status; int ret = 0; IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); switch (event) { case RECV_I_CMD: /* Optimize for the common case */ /* FIXME: must check for remote_busy below */ IRDA_DEBUG(4, "%s(), event=%s nr=%d, vs=%d, ns=%d, " "vr=%d, pf=%d\n", __FUNCTION__, irlap_event[event], info->nr, self->vs, info->ns, self->vr, info->pf); self->retry_count = 0; ns_status = irlap_validate_ns_received(self, info->ns); nr_status = irlap_validate_nr_received(self, info->nr); /* * Check for expected I(nformation) frame */ if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) { /* Update Vr (next frame for us to receive) */ self->vr = (self->vr + 1) % 8; /* Update Nr received */ irlap_update_nr_received(self, info->nr); /* * poll bit cleared? */ if (!info->pf) { self->ack_required = TRUE; /* * Starting WD-timer here is optional, but * not recommended. Note 6 IrLAP p. 83 */#if 0 irda_start_timer(WD_TIMER, self->wd_timeout);#endif /* Keep state, do not move this line */ irlap_next_state(self, LAP_NRM_S); irlap_data_indication(self, skb, FALSE); break; } else { /* * We should wait before sending RR, and * also before changing to XMIT_S * state. (note 1, IrLAP p. 82) */ irlap_wait_min_turn_around(self, &self->qos_tx); /* * Give higher layers a chance to * immediately reply with some data before * we decide if we should send a RR frame * or not */ irlap_data_indication(self, skb, FALSE); /* Any pending data requests? */ if (!skb_queue_empty(&self->txq) && (self->window > 0)) { self->ack_required = TRUE; del_timer(&self->wd_timer); irlap_next_state(self, LAP_XMIT_S); } else { irlap_send_rr_frame(self, RSP_FRAME); irlap_start_wd_timer(self, self->wd_timeout); /* Keep the state */ irlap_next_state(self, LAP_NRM_S); } break; } } /* * Check for Unexpected next to send (Ns) */ if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED)) { /* Unexpected next to send, with final bit cleared */ if (!info->pf) { irlap_update_nr_received(self, info->nr); irlap_start_wd_timer(self, self->wd_timeout); } else { /* Update Nr received */ irlap_update_nr_received(self, info->nr); irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_rr_frame(self, RSP_FRAME); irlap_start_wd_timer(self, self->wd_timeout); } break; } /* * Unexpected Next to Receive(NR) ? */ if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED)) { if (info->pf) { IRDA_DEBUG(4, "RECV_I_RSP: frame(s) lost\n"); self->vr = (self->vr + 1) % 8; /* Update Nr received */ irlap_update_nr_received(self, info->nr); /* Resend rejected frames */ irlap_resend_rejected_frames(self, RSP_FRAME); /* Keep state, do not move this line */ irlap_next_state(self, LAP_NRM_S); irlap_data_indication(self, skb, FALSE); irlap_start_wd_timer(self, self->wd_timeout); break; } /* * This is not documented in IrLAP!! Unexpected NR * with poll bit cleared */ if (!info->pf) { self->vr = (self->vr + 1) % 8; /* Update Nr received */ irlap_update_nr_received(self, info->nr); /* Keep state, do not move this line */ irlap_next_state(self, LAP_NRM_S); irlap_data_indication(self, skb, FALSE); irlap_start_wd_timer(self, self->wd_timeout); } break; } if (ret == NR_INVALID) { IRDA_DEBUG(0, "NRM_S, NR_INVALID not implemented!\n"); } if (ret == NS_INVALID) { IRDA_DEBUG(0, "NRM_S, NS_INVALID not implemented!\n"); } break; case RECV_UI_FRAME: /* * poll bit cleared? */ if (!info->pf) { irlap_data_indication(self, skb, TRUE); irlap_next_state(self, LAP_NRM_S); /* Keep state */ } else { /* * Any pending data requests? */ if (!skb_queue_empty(&self->txq) && (self->window > 0) && !self->remote_busy) { irlap_data_indication(self, skb, TRUE); del_timer(&self->wd_timer); irlap_next_state(self, LAP_XMIT_S); } else { irlap_data_indication(self, skb, TRUE); irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_rr_frame(self, RSP_FRAME); self->ack_required = FALSE; irlap_start_wd_timer(self, self->wd_timeout); /* Keep the state */ irlap_next_state(self, LAP_NRM_S); } } break; case RECV_RR_CMD: self->retry_count = 0; /* * Nr as expected? */ nr_status = irlap_validate_nr_received(self, info->nr); if (nr_status == NR_EXPECTED) { if (!skb_queue_empty(&self->txq) && (self->window > 0)) { self->remote_busy = FALSE; /* Update Nr received */ irlap_update_nr_received(self, info->nr); del_timer(&self->wd_timer); irlap_wait_min_turn_around(self, &self->qos_tx); irlap_next_state(self, LAP_XMIT_S); } else { self->remote_busy = FALSE; /* Update Nr received */ irlap_update_nr_received(self, info->nr); irlap_wait_min_turn_around(self, &self->qos_tx); irlap_start_wd_timer(self, self->wd_timeout); /* Note : if the link is idle (this case), * we never go in XMIT_S, so we never get a * chance to process any DISCONNECT_REQUEST. * Do it now ! - Jean II */ if (self->disconnect_pending) { /* Disconnect */ irlap_send_rd_frame(self); irlap_flush_all_queues(self); irlap_next_state(self, LAP_SCLOSE); } else { /* Just send back pf bit */ irlap_send_rr_frame(self, RSP_FRAME); irlap_next_state(self, LAP_NRM_S); } } } else if (nr_status == NR_UNEXPECTED) { self->remote_busy = FALSE; irlap_update_nr_received(self, info->nr); irlap_resend_rejected_frames(self, RSP_FRAME); irlap_start_wd_timer(self, self->wd_timeout); /* Keep state */ irlap_next_state(self, LAP_NRM_S); } else { IRDA_DEBUG(1, "%s(), invalid nr not implemented!\n", __FUNCTION__); } break; case RECV_SNRM_CMD: /* SNRM frame is not allowed to contain an I-field */ if (!info) { del_timer(&self->wd_timer); IRDA_DEBUG(1, "%s(), received SNRM cmd\n", __FUNCTION__); irlap_next_state(self, LAP_RESET_CHECK); irlap_reset_indication(self); } else { IRDA_DEBUG(0, "%s(), SNRM frame contained an I-field!\n", __FUNCTION__); } break; case RECV_REJ_CMD: irlap_update_nr_received(self, info->nr); if (self->remote_busy) { irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_rr_frame(self, RSP_FRAME); } else irlap_resend_rejected_frames(self, RSP_FRAME); irlap_start_wd_timer(self, self->wd_timeout); break; case RECV_SREJ_CMD: irlap_update_nr_received(self, info->nr); if (self->remote_busy) { irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_rr_frame(self, RSP_FRAME); } else irlap_resend_rejected_frame(self, RSP_FRAME); irlap_start_wd_timer(self, self->wd_timeout); break; case WD_TIMER_EXPIRED: /* * Wait until retry_count * n matches negotiated threshold/ * disconnect time (note 2 in IrLAP p. 82) * * Similar to irlap_state_nrm_p() -> FINAL_TIMER_EXPIRED * Note : self->wd_timeout = (self->final_timeout * 2), * which explain why we use (self->N2 / 2) here !!! * Jean II */ IRDA_DEBUG(1, "%s(), retry_count = %d\n", __FUNCTION__, self->retry_count); if (self->retry_count < (self->N2 / 2)) { /* No retry, just wait for primary */ irlap_start_wd_timer(self, self->wd_timeout); self->retry_count++; if((self->retry_count % (self->N1 / 2)) == 0) irlap_status_indication(self, STATUS_NO_ACTIVITY); } else { irlap_apply_default_connection_parameters(self); /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); irlap_disconnect_indication(self, LAP_NO_RESPONSE); } break; case RECV_DISC_CMD: /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); /* Send disconnect response */ irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_ua_response_frame(self, NULL); del_timer(&self->wd_timer); irlap_flush_all_queues(self); /* Set default link parameters */ irlap_apply_default_connection_parameters(self); irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; case RECV_DISCOVERY_XID_CMD: irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_rr_frame(self, RSP_FRAME); self->ack_required = TRUE; irlap_start_wd_timer(self, self->wd_timeout); irlap_next_state(self, LAP_NRM_S); break; case RECV_TEST_CMD: /* Remove test frame header (only LAP header in NRM) */ skb_pull(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); irlap_wait_min_turn_around(self, &self->qos_tx); irlap_start_wd_timer(self, self->wd_timeout); /* Send response (info will be copied) */ irlap_send_test_frame(self, self->caddr, info->daddr, skb); break; default: IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__, event, irlap_event[event]); ret = -EINVAL; break; } return ret;}/* * Function irlap_state_sclose (self, event, skb, info) */static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info){ int ret = 0; IRDA_DEBUG(1, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return -ENODEV;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); switch (event) { case RECV_DISC_CMD: /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); /* Send disconnect response */ irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_ua_response_frame(self, NULL); del_timer(&self->wd_timer); /* Set default link parameters */ irlap_apply_default_connection_parameters(self); irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; case RECV_DM_RSP: /* IrLAP-1.1 p.82: in SCLOSE, S and I type RSP frames * shall take us down into default NDM state, like DM_RSP */ case RECV_RR_RSP: case RECV_RNR_RSP: case RECV_REJ_RSP: case RECV_SREJ_RSP: case RECV_I_RSP: /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); del_timer(&self->wd_timer); irlap_apply_default_connection_parameters(self); irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; case WD_TIMER_EXPIRED: /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); irlap_apply_default_connection_parameters(self); irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; default: /* IrLAP-1.1 p.82: in SCLOSE, basically any received frame * with pf=1 shall restart the wd-timer and resend the rd:rsp */ if (info != NULL && info->pf) { del_timer(&self->wd_timer); irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_rd_frame(self); irlap_start_wd_timer(self, self->wd_timeout); break; /* stay in SCLOSE */ } IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__, event, irlap_event[event]); ret = -EINVAL; break; } return -1;}static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info){ int ret = 0; IRDA_DEBUG(1, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]); IRDA_ASSERT(self != NULL, return -ENODEV;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); switch (event) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -