📄 irlap_event.c
字号:
#ifdef CONFIG_IRDA_ULTRA /* Send any pending Ultra frames if any */ if (!skb_queue_empty(&self->txq_ultra)) { /* We don't send the frame, just post an event. * Also, previously this code was in timer.c... * Jean II */ ret = (*state[self->state])(self, SEND_UI_FRAME, NULL, NULL); }#endif /* CONFIG_IRDA_ULTRA */ /* Check if we should try to connect. * This code was previously in irlap_do_event() */ if (self->connect_pending) { self->connect_pending = FALSE; /* This one *should* not pend in this state, except * if a socket try to connect and immediately * disconnect. - clear - Jean II */ if (self->disconnect_pending) irlap_disconnect_indication(self, LAP_DISC_INDICATION); else ret = (*state[self->state])(self, CONNECT_REQUEST, NULL, NULL); self->disconnect_pending = FALSE; } /* Note : one way to test if this code works well (including * media busy and small busy) is to create a user space * application generating an Ultra packet every 3.05 sec (or * 2.95 sec) and to see how it interact with discovery. * It's fairly easy to check that no packet is lost, that the * packets are postponed during discovery and that after * discovery indication you have a 100ms "gap". * As connection request and Ultra are now processed the same * way, this avoid the tedious job of trying IrLAP connection * in all those cases... * Jean II */ break;#ifdef CONFIG_IRDA_ULTRA case SEND_UI_FRAME: { int i; /* Only allowed to repeat an operation twice */ for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) { skb = skb_dequeue(&self->txq_ultra); if (skb) irlap_send_ui_frame(self, skb, CBROADCAST, CMD_FRAME); else break; /* irlap_send_ui_frame() won't increase skb reference * count, so no dev_kfree_skb() - Jean II */ } if (i == 2) { /* Force us to listen 500 ms again */ irda_device_set_media_busy(self->netdev, TRUE); } break; } case RECV_UI_FRAME: /* Only accept broadcast frames in NDM mode */ if (info->caddr != CBROADCAST) { IRDA_DEBUG(0, "%s(), not a broadcast frame!\n", __FUNCTION__); } else irlap_unitdata_indication(self, skb); break;#endif /* CONFIG_IRDA_ULTRA */ case RECV_TEST_CMD: /* Remove test frame header */ skb_pull(skb, sizeof(struct test_frame)); /* * Send response. This skb will not be sent out again, and * will only be used to send out the same info as the cmd */ irlap_send_test_frame(self, CBROADCAST, info->daddr, skb); break; case RECV_TEST_RSP: IRDA_DEBUG(0, "%s() not implemented!\n", __FUNCTION__); break; default: IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__, irlap_event[event]); ret = -1; break; } return ret;}/* * Function irlap_state_query (event, skb, info) * * QUERY state * */static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info){ int ret = 0; IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); switch (event) { case RECV_DISCOVERY_XID_RSP: IRDA_ASSERT(info != NULL, return -1;); IRDA_ASSERT(info->discovery != NULL, return -1;); IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__, info->discovery->data.daddr); if (!self->discovery_log) { IRDA_WARNING("%s: discovery log is gone! " "maybe the discovery timeout has been set" " too short?\n", __FUNCTION__); break; } hashbin_insert(self->discovery_log, (irda_queue_t *) info->discovery, info->discovery->data.daddr, NULL); /* Keep state */ /* irlap_next_state(self, LAP_QUERY); */ break; case RECV_DISCOVERY_XID_CMD: /* Yes, it is possible to receive those frames in this mode. * Note that most often the last discovery request won't * occur here but in NDM state (see my comment there). * What should we do ? * Not much. We are currently performing our own discovery, * therefore we can't answer those frames. We don't want * to change state either. We just pass the info to * IrLMP who will put it in the log (and post an event). * Jean II */ IRDA_ASSERT(info != NULL, return -1;); IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __FUNCTION__, info->s); /* Last discovery request ? */ if (info->s == 0xff) irlap_discovery_indication(self, info->discovery); break; case SLOT_TIMER_EXPIRED: /* * Wait a little longer if we detect an incoming frame. This * is not mentioned in the spec, but is a good thing to do, * since we want to work even with devices that violate the * timing requirements. */ if (irda_device_is_receiving(self->netdev) && !self->add_wait) { IRDA_DEBUG(2, "%s(), device is slow to answer, " "waiting some more!\n", __FUNCTION__); irlap_start_slot_timer(self, msecs_to_jiffies(10)); self->add_wait = TRUE; return ret; } self->add_wait = FALSE; if (self->s < self->S) { irlap_send_discovery_xid_frame(self, self->S, self->s, TRUE, self->discovery_cmd); self->s++; irlap_start_slot_timer(self, self->slot_timeout); /* Keep state */ irlap_next_state(self, LAP_QUERY); } else { /* This is the final slot! */ irlap_send_discovery_xid_frame(self, self->S, 0xff, TRUE, self->discovery_cmd); /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); /* * We are now finished with the discovery procedure, * so now we must return the results */ irlap_discovery_confirm(self, self->discovery_log); /* IrLMP should now have taken care of the log */ self->discovery_log = NULL; } break; default: IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__, irlap_event[event]); ret = -1; break; } return ret;}/* * Function irlap_state_reply (self, event, skb, info) * * REPLY, we have received a XID discovery frame from a device and we * are waiting for the right time slot to send a response XID frame * */static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info){ discovery_t *discovery_rsp; int ret=0; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); switch (event) { case QUERY_TIMER_EXPIRED: IRDA_DEBUG(0, "%s(), QUERY_TIMER_EXPIRED <%ld>\n", __FUNCTION__, jiffies); irlap_next_state(self, LAP_NDM); break; case RECV_DISCOVERY_XID_CMD: IRDA_ASSERT(info != NULL, return -1;); /* Last frame? */ if (info->s == 0xff) { del_timer(&self->query_timer); /* info->log.condition = REMOTE; */ /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); irlap_discovery_indication(self, info->discovery); } else { /* If it's our slot, send our reply */ if ((info->s >= self->slot) && (!self->frame_sent)) { discovery_rsp = irlmp_get_discovery_response(); discovery_rsp->data.daddr = info->daddr; irlap_send_discovery_xid_frame(self, info->S, self->slot, FALSE, discovery_rsp); self->frame_sent = TRUE; } /* Readjust our timer to accomodate devices * doing faster or slower discovery than us... * Jean II */ irlap_start_query_timer(self, info->S, info->s); /* Keep state */ //irlap_next_state(self, LAP_REPLY); } break; default: IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__, event, irlap_event[event]); ret = -1; break; } return ret;}/* * Function irlap_state_conn (event, skb, info) * * CONN, we have received a SNRM command and is waiting for the upper * layer to accept or refuse connection * */static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info){ 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 CONNECT_RESPONSE: skb_pull(skb, sizeof(struct snrm_frame)); IRDA_ASSERT(self->netdev != NULL, return -1;); irlap_qos_negotiate(self, skb); irlap_initiate_connection_state(self); /* * Applying the parameters now will make sure we change speed * *after* we have sent the next frame */ irlap_apply_connection_parameters(self, FALSE); /* * Sending this frame will force a speed change after it has * been sent (i.e. the frame will be sent at 9600). */ irlap_send_ua_response_frame(self, &self->qos_rx);#if 0 /* * We are allowed to send two frames, but this may increase * the connect latency, so lets not do it for now. */ /* This is full of good intentions, but doesn't work in * practice. * After sending the first UA response, we switch the * dongle to the negotiated speed, which is usually * different than 9600 kb/s. * From there, there is two solutions : * 1) The other end has received the first UA response : * it will set up the connection, move to state LAP_NRM_P, * and will ignore and drop the second UA response. * Actually, it's even worse : the other side will almost * immediately send a RR that will likely collide with the * UA response (depending on negotiated turnaround). * 2) The other end has not received the first UA response, * will stay at 9600 and will never see the second UA response. * Jean II */ irlap_send_ua_response_frame(self, &self->qos_rx);#endif /* * The WD-timer could be set to the duration of the P-timer * for this case, but it is recommended to use twice the * value (note 3 IrLAP p. 60). */ irlap_start_wd_timer(self, self->wd_timeout); irlap_next_state(self, LAP_NRM_S); break; case RECV_DISCOVERY_XID_CMD: IRDA_DEBUG(3, "%s(), event RECV_DISCOVER_XID_CMD!\n", __FUNCTION__); irlap_next_state(self, LAP_NDM); break; case DISCONNECT_REQUEST: IRDA_DEBUG(0, "%s(), Disconnect request!\n", __FUNCTION__); irlap_send_dm_frame(self); irlap_next_state( self, LAP_NDM); irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; default: IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__, event, irlap_event[event]); ret = -1; break; } return ret;}/* * Function irlap_state_setup (event, skb, frame) * * SETUP state, The local layer has transmitted a SNRM command frame to * a remote peer layer and is awaiting a reply . * */static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info){ int ret = 0; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); switch (event) { case FINAL_TIMER_EXPIRED: if (self->retry_count < self->N3) {/* * Perform random backoff, Wait a random number of time units, minimum * duration half the time taken to transmitt a SNRM frame, maximum duration * 1.5 times the time taken to transmit a SNRM frame. So this time should * between 15 msecs and 45 msecs. */ irlap_start_backoff_timer(self, msecs_to_jiffies(20 + (jiffies % 30))); } else { /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); irlap_disconnect_indication(self, LAP_FOUND_NONE); } break; case BACKOFF_TIMER_EXPIRED: irlap_send_snrm_frame(self, &self->qos_rx); irlap_start_final_timer(self, self->final_timeout); self->retry_count++; break; case RECV_SNRM_CMD: IRDA_DEBUG(4, "%s(), SNRM battle!\n", __FUNCTION__); IRDA_ASSERT(skb != NULL, return 0;); IRDA_ASSERT(info != NULL, return 0;); /* * The device with the largest device address wins the battle * (both have sent a SNRM command!) */ if (info &&(info->daddr > self->saddr)) { del_timer(&self->final_timer); irlap_initiate_connection_state(self); IRDA_ASSERT(self->netdev != NULL, return -1;); skb_pull(skb, sizeof(struct snrm_frame)); irlap_qos_negotiate(self, skb); /* Send UA frame and then change link settings */ irlap_apply_connection_parameters(self, FALSE); irlap_send_ua_response_frame(self, &self->qos_rx); irlap_next_state(self, LAP_NRM_S); irlap_connect_confirm(self, skb); /* * The WD-timer could be set to the duration of the * P-timer for this case, but it is recommended * to use twice the value (note 3 IrLAP p. 60). */ irlap_start_wd_timer(self, self->wd_timeout); } else { /* We just ignore the other device! */ irlap_next_state(self, LAP_SETUP); } break; case RECV_UA_RSP: /* Stop F-timer */ del_timer(&self->final_timer); /* Initiate connection state */ irlap_initiate_connection_state(self); /* Negotiate connection parameters */ IRDA_ASSERT(skb->len > 10, return -1;); skb_pull(skb, sizeof(struct ua_frame)); IRDA_ASSERT(self->netdev != NULL, return -1;); irlap_qos_negotiate(self, skb); /* Set the new link setting *now* (before the rr frame) */ irlap_apply_connection_parameters(self, TRUE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -