diff options
Diffstat (limited to 'net/irda/irlap_event.c')
-rw-r--r-- | net/irda/irlap_event.c | 2316 |
1 files changed, 0 insertions, 2316 deletions
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c deleted file mode 100644 index 0e1b4d79f745..000000000000 --- a/net/irda/irlap_event.c +++ /dev/null @@ -1,2316 +0,0 @@ -/********************************************************************* - * - * Filename: irlap_event.c - * Version: 0.9 - * Description: IrLAP state machine implementation - * Status: Experimental. - * Author: Dag Brattli <dag@brattli.net> - * Created at: Sat Aug 16 00:59:29 1997 - * Modified at: Sat Dec 25 21:07:57 1999 - * Modified by: Dag Brattli <dag@brattli.net> - * - * Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>, - * Copyright (c) 1998 Thomas Davis <ratbert@radiks.net> - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/skbuff.h> -#include <linux/slab.h> - -#include <net/irda/irda.h> -#include <net/irda/irlap_event.h> - -#include <net/irda/timer.h> -#include <net/irda/irlap.h> -#include <net/irda/irlap_frame.h> -#include <net/irda/qos.h> -#include <net/irda/parameters.h> -#include <net/irda/irlmp.h> /* irlmp_flow_indication(), ... */ - -#include <net/irda/irda_device.h> - -#ifdef CONFIG_IRDA_FAST_RR -int sysctl_fast_poll_increase = 50; -#endif - -static int irlap_state_ndm (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_query (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reply (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_conn (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_setup (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_xmit_p (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_pclose (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_nrm_p (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reset (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_nrm_s (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_xmit_s (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_sclose (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event, - struct sk_buff *, struct irlap_info *); - -static const char *const irlap_event[] __maybe_unused = { - "DISCOVERY_REQUEST", - "CONNECT_REQUEST", - "CONNECT_RESPONSE", - "DISCONNECT_REQUEST", - "DATA_REQUEST", - "RESET_REQUEST", - "RESET_RESPONSE", - "SEND_I_CMD", - "SEND_UI_FRAME", - "RECV_DISCOVERY_XID_CMD", - "RECV_DISCOVERY_XID_RSP", - "RECV_SNRM_CMD", - "RECV_TEST_CMD", - "RECV_TEST_RSP", - "RECV_UA_RSP", - "RECV_DM_RSP", - "RECV_RD_RSP", - "RECV_I_CMD", - "RECV_I_RSP", - "RECV_UI_FRAME", - "RECV_FRMR_RSP", - "RECV_RR_CMD", - "RECV_RR_RSP", - "RECV_RNR_CMD", - "RECV_RNR_RSP", - "RECV_REJ_CMD", - "RECV_REJ_RSP", - "RECV_SREJ_CMD", - "RECV_SREJ_RSP", - "RECV_DISC_CMD", - "SLOT_TIMER_EXPIRED", - "QUERY_TIMER_EXPIRED", - "FINAL_TIMER_EXPIRED", - "POLL_TIMER_EXPIRED", - "DISCOVERY_TIMER_EXPIRED", - "WD_TIMER_EXPIRED", - "BACKOFF_TIMER_EXPIRED", - "MEDIA_BUSY_TIMER_EXPIRED", -}; - -const char *const irlap_state[] = { - "LAP_NDM", - "LAP_QUERY", - "LAP_REPLY", - "LAP_CONN", - "LAP_SETUP", - "LAP_OFFLINE", - "LAP_XMIT_P", - "LAP_PCLOSE", - "LAP_NRM_P", - "LAP_RESET_WAIT", - "LAP_RESET", - "LAP_NRM_S", - "LAP_XMIT_S", - "LAP_SCLOSE", - "LAP_RESET_CHECK", -}; - -static int (*state[])(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) = -{ - irlap_state_ndm, - irlap_state_query, - irlap_state_reply, - irlap_state_conn, - irlap_state_setup, - irlap_state_offline, - irlap_state_xmit_p, - irlap_state_pclose, - irlap_state_nrm_p, - irlap_state_reset_wait, - irlap_state_reset, - irlap_state_nrm_s, - irlap_state_xmit_s, - irlap_state_sclose, - irlap_state_reset_check, -}; - -/* - * Function irda_poll_timer_expired (data) - * - * Poll timer has expired. Normally we must now send a RR frame to the - * remote device - */ -static void irlap_poll_timer_expired(void *data) -{ - struct irlap_cb *self = (struct irlap_cb *) data; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL); -} - -/* - * Calculate and set time before we will have to send back the pf bit - * to the peer. Use in primary. - * Make sure that state is XMIT_P/XMIT_S when calling this function - * (and that nobody messed up with the state). - Jean II - */ -static void irlap_start_poll_timer(struct irlap_cb *self, int timeout) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - -#ifdef CONFIG_IRDA_FAST_RR - /* - * Send out the RR frames faster if our own transmit queue is empty, or - * if the peer is busy. The effect is a much faster conversation - */ - if (skb_queue_empty(&self->txq) || self->remote_busy) { - if (self->fast_RR == TRUE) { - /* - * Assert that the fast poll timer has not reached the - * normal poll timer yet - */ - if (self->fast_RR_timeout < timeout) { - /* - * FIXME: this should be a more configurable - * function - */ - self->fast_RR_timeout += - (sysctl_fast_poll_increase * HZ/1000); - - /* Use this fast(er) timeout instead */ - timeout = self->fast_RR_timeout; - } - } else { - self->fast_RR = TRUE; - - /* Start with just 0 ms */ - self->fast_RR_timeout = 0; - timeout = 0; - } - } else - self->fast_RR = FALSE; - - pr_debug("%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies); -#endif /* CONFIG_IRDA_FAST_RR */ - - if (timeout == 0) - irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL); - else - irda_start_timer(&self->poll_timer, timeout, self, - irlap_poll_timer_expired); -} - -/* - * Function irlap_do_event (event, skb, info) - * - * Rushes through the state machine without any delay. If state == XMIT - * then send queued data frames. - */ -void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret; - - if (!self || self->magic != LAP_MAGIC) - return; - - pr_debug("%s(), event = %s, state = %s\n", __func__, - irlap_event[event], irlap_state[self->state]); - - ret = (*state[self->state])(self, event, skb, info); - - /* - * Check if there are any pending events that needs to be executed - */ - switch (self->state) { - case LAP_XMIT_P: /* FALLTHROUGH */ - case LAP_XMIT_S: - /* - * We just received the pf bit and are at the beginning - * of a new LAP transmit window. - * Check if there are any queued data frames, and do not - * try to disconnect link if we send any data frames, since - * that will change the state away form XMIT - */ - pr_debug("%s() : queue len = %d\n", __func__, - skb_queue_len(&self->txq)); - - if (!skb_queue_empty(&self->txq)) { - /* Prevent race conditions with irlap_data_request() */ - self->local_busy = TRUE; - - /* Theory of operation. - * We send frames up to when we fill the window or - * reach line capacity. Those frames will queue up - * in the device queue, and the driver will slowly - * send them. - * After each frame that we send, we poll the higher - * layer for more data. It's the right time to do - * that because the link layer need to perform the mtt - * and then send the first frame, so we can afford - * to send a bit of time in kernel space. - * The explicit flow indication allow to minimise - * buffers (== lower latency), to avoid higher layer - * polling via timers (== less context switches) and - * to implement a crude scheduler - Jean II */ - - /* Try to send away all queued data frames */ - while ((skb = skb_dequeue(&self->txq)) != NULL) { - /* Send one frame */ - ret = (*state[self->state])(self, SEND_I_CMD, - skb, NULL); - /* Drop reference count. - * It will be increase as needed in - * irlap_send_data_xxx() */ - kfree_skb(skb); - - /* Poll the higher layers for one more frame */ - irlmp_flow_indication(self->notify.instance, - FLOW_START); - - if (ret == -EPROTO) - break; /* Try again later! */ - } - /* Finished transmitting */ - self->local_busy = FALSE; - } else if (self->disconnect_pending) { - self->disconnect_pending = FALSE; - - ret = (*state[self->state])(self, DISCONNECT_REQUEST, - NULL, NULL); - } - break; -/* case LAP_NDM: */ -/* case LAP_CONN: */ -/* case LAP_RESET_WAIT: */ -/* case LAP_RESET_CHECK: */ - default: - break; - } -} - -/* - * Function irlap_state_ndm (event, skb, frame) - * - * NDM (Normal Disconnected Mode) state - * - */ -static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - discovery_t *discovery_rsp; - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case CONNECT_REQUEST: - IRDA_ASSERT(self->netdev != NULL, return -1;); - - if (self->media_busy) { - /* Note : this will never happen, because we test - * media busy in irlap_connect_request() and - * postpone the event... - Jean II */ - pr_debug("%s(), CONNECT_REQUEST: media busy!\n", - __func__); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_MEDIA_BUSY); - } else { - irlap_send_snrm_frame(self, &self->qos_rx); - - /* Start Final-bit timer */ - irlap_start_final_timer(self, self->final_timeout); - - self->retry_count = 0; - irlap_next_state(self, LAP_SETUP); - } - break; - case RECV_SNRM_CMD: - /* Check if the frame contains and I field */ - if (info) { - self->daddr = info->daddr; - self->caddr = info->caddr; - - irlap_next_state(self, LAP_CONN); - - irlap_connect_indication(self, skb); - } else { - pr_debug("%s(), SNRM frame does not contain an I field!\n", - __func__); - } - break; - case DISCOVERY_REQUEST: - IRDA_ASSERT(info != NULL, return -1;); - - if (self->media_busy) { - pr_debug("%s(), DISCOVERY_REQUEST: media busy!\n", - __func__); - /* irlap->log.condition = MEDIA_BUSY; */ - - /* This will make IrLMP try again */ - irlap_discovery_confirm(self, NULL); - /* Note : the discovery log is not cleaned up here, - * it will be done in irlap_discovery_request() - * Jean II */ - return 0; - } - - self->S = info->S; - self->s = info->s; - irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE, - info->discovery); - self->frame_sent = FALSE; - self->s++; - - irlap_start_slot_timer(self, self->slot_timeout); - irlap_next_state(self, LAP_QUERY); - break; - case RECV_DISCOVERY_XID_CMD: - IRDA_ASSERT(info != NULL, return -1;); - - /* Assert that this is not the final slot */ - if (info->s <= info->S) { - self->slot = irlap_generate_rand_time_slot(info->S, - info->s); - if (self->slot == info->s) { - 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; - } else - self->frame_sent = FALSE; - - /* - * Go to reply state until end of discovery to - * inhibit our own transmissions. Set the timer - * to not stay forever there... Jean II - */ - irlap_start_query_timer(self, info->S, info->s); - irlap_next_state(self, LAP_REPLY); - } else { - /* This is the final slot. How is it possible ? - * This would happen is both discoveries are just slightly - * offset (if they are in sync, all packets are lost). - * Most often, all the discovery requests will be received - * in QUERY state (see my comment there), except for the - * last frame that will come here. - * The big trouble when it happen is that active discovery - * doesn't happen, because nobody answer the discoveries - * frame of the other guy, so the log shows up empty. - * What should we do ? - * Not much. It's too late to answer those discovery frames, - * so we just pass the info to IrLMP who will put it in the - * log (and post an event). - * Another cause would be devices that do discovery much - * slower than us, however the latest fixes should minimise - * those cases... - * Jean II - */ - pr_debug("%s(), Receiving final discovery request, missed the discovery slots :-(\n", - __func__); - - /* Last discovery request -> in the log */ - irlap_discovery_indication(self, info->discovery); - } - break; - case MEDIA_BUSY_TIMER_EXPIRED: - /* A bunch of events may be postponed because the media is - * busy (usually immediately after we close a connection), - * or while we are doing discovery (state query/reply). - * In all those cases, the media busy flag will be cleared - * when it's OK for us to process those postponed events. - * This event is not mentioned in the state machines in the - * IrLAP spec. It's because they didn't consider Ultra and - * postponing connection request is optional. - * Jean II */ -#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) { - pr_debug("%s(), not a broadcast frame!\n", - __func__); - } 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: - pr_debug("%s() not implemented!\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %s\n", __func__, - 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;); - - pr_debug("%s(), daddr=%08x\n", __func__, - info->discovery->data.daddr); - - if (!self->discovery_log) { - net_warn_ratelimited("%s: discovery log is gone! maybe the discovery timeout has been set too short?\n", - __func__); - 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;); - - pr_debug("%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", - __func__, 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) { - pr_debug("%s(), device is slow to answer, waiting some more!\n", - __func__); - 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: - pr_debug("%s(), Unknown event %s\n", __func__, - 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_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case QUERY_TIMER_EXPIRED: - pr_debug("%s(), QUERY_TIMER_EXPIRED <%ld>\n", - __func__, 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 accommodate 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: - pr_debug("%s(), Unknown event %d, %s\n", __func__, - 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; - - pr_debug("%s(), event=%s\n", __func__, 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: - pr_debug("%s(), event RECV_DISCOVER_XID_CMD!\n", - __func__); - irlap_next_state(self, LAP_NDM); - - break; - case DISCONNECT_REQUEST: - pr_debug("%s(), Disconnect request!\n", __func__); - irlap_send_dm_frame(self); - irlap_next_state( self, LAP_NDM); - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - default: - pr_debug("%s(), Unknown event %d, %s\n", __func__, - 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_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: - pr_debug("%s(), SNRM battle!\n", __func__); - - 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); - self->retry_count = 0; - - /* Wait for turnaround time to give a chance to the other - * device to be ready to receive us. - * Note : the time to switch speed is typically larger - * than the turnaround time, but as we don't have the other - * side speed switch time, that's our best guess... - * Jean II */ - irlap_wait_min_turn_around(self, &self->qos_tx); - - /* This frame will actually be sent at the new speed */ - irlap_send_rr_frame(self, CMD_FRAME); - - /* The timer is set to half the normal timer to quickly - * detect a failure to negotiate the new connection - * parameters. IrLAP 6.11.3.2, note 3. - * Note that currently we don't process this failure - * properly, as we should do a quick disconnect. - * Jean II */ - irlap_start_final_timer(self, self->final_timeout/2); - irlap_next_state(self, LAP_NRM_P); - - irlap_connect_confirm(self, skb); - break; - case RECV_DM_RSP: /* FALLTHROUGH */ - case RECV_DISC_CMD: - del_timer(&self->final_timer); - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - default: - pr_debug("%s(), Unknown event %d, %s\n", __func__, - event, irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_offline (self, event, skb, info) - * - * OFFLINE state, not used for now! - * - */ -static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - pr_debug("%s(), Unknown event\n", __func__); - - return -1; -} - -/* - * Function irlap_state_xmit_p (self, event, skb, info) - * - * XMIT, Only the primary station has right to transmit, and we - * therefore do not expect to receive any transmissions from other - * stations. - * - */ -static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - switch (event) { - case SEND_I_CMD: - /* - * Only send frame if send-window > 0. - */ - if ((self->window > 0) && (!self->remote_busy)) { - int nextfit; -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - struct sk_buff *skb_next; - - /* With DYNAMIC_WINDOW, we keep the window size - * maximum, and adapt on the packets we are sending. - * At 115k, we can send only 2 packets of 2048 bytes - * in a 500 ms turnaround. Without this option, we - * would always limit the window to 2. With this - * option, if we send smaller packets, we can send - * up to 7 of them (always depending on QoS). - * Jean II */ - - /* Look at the next skb. This is safe, as we are - * the only consumer of the Tx queue (if we are not, - * we have other problems) - Jean II */ - skb_next = skb_peek(&self->txq); - - /* Check if a subsequent skb exist and would fit in - * the current window (with respect to turnaround - * time). - * This allow us to properly mark the current packet - * with the pf bit, to avoid falling back on the - * second test below, and avoid waiting the - * end of the window and sending a extra RR. - * Note : (skb_next != NULL) <=> (skb_queue_len() > 0) - * Jean II */ - nextfit = ((skb_next != NULL) && - ((skb_next->len + skb->len) <= - self->bytes_left)); - - /* - * The current packet may not fit ! Because of test - * above, this should not happen any more !!! - * Test if we have transmitted more bytes over the - * link than its possible to do with the current - * speed and turn-around-time. - */ - if((!nextfit) && (skb->len > self->bytes_left)) { - pr_debug("%s(), Not allowed to transmit more bytes!\n", - __func__); - /* Requeue the skb */ - skb_queue_head(&self->txq, skb_get(skb)); - /* - * We should switch state to LAP_NRM_P, but - * that is not possible since we must be sure - * that we poll the other side. Since we have - * used up our time, the poll timer should - * trigger anyway now, so we just wait for it - * DB - */ - /* - * Sorry, but that's not totally true. If - * we send 2000B packets, we may wait another - * 1000B until our turnaround expire. That's - * why we need to be proactive in avoiding - * coming here. - Jean II - */ - return -EPROTO; - } - - /* Subtract space used by this skb */ - self->bytes_left -= skb->len; -#else /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* Window has been adjusted for the max packet - * size, so much simpler... - Jean II */ - nextfit = !skb_queue_empty(&self->txq); -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* - * Send data with poll bit cleared only if window > 1 - * and there is more frames after this one to be sent - */ - if ((self->window > 1) && (nextfit)) { - /* More packet to send in current window */ - irlap_send_data_primary(self, skb); - irlap_next_state(self, LAP_XMIT_P); - } else { - /* Final packet of window */ - irlap_send_data_primary_poll(self, skb); - - /* - * Make sure state machine does not try to send - * any more frames - */ - ret = -EPROTO; - } -#ifdef CONFIG_IRDA_FAST_RR - /* Peer may want to reply immediately */ - self->fast_RR = FALSE; -#endif /* CONFIG_IRDA_FAST_RR */ - } else { - pr_debug("%s(), Unable to send! remote busy?\n", - __func__); - skb_queue_head(&self->txq, skb_get(skb)); - - /* - * The next ret is important, because it tells - * irlap_next_state _not_ to deliver more frames - */ - ret = -EPROTO; - } - break; - case POLL_TIMER_EXPIRED: - pr_debug("%s(), POLL_TIMER_EXPIRED <%ld>\n", - __func__, jiffies); - irlap_send_rr_frame(self, CMD_FRAME); - /* Return to NRM properly - Jean II */ - self->window = self->window_size; -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - /* Allowed to transmit a maximum number of bytes again. */ - self->bytes_left = self->line_capacity; -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_NRM_P); - break; - case DISCONNECT_REQUEST: - del_timer(&self->poll_timer); - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_disc_frame(self); - irlap_flush_all_queues(self); - irlap_start_final_timer(self, self->final_timeout); - self->retry_count = 0; - irlap_next_state(self, LAP_PCLOSE); - break; - case DATA_REQUEST: - /* Nothing to do, irlap_do_event() will send the packet - * when we return... - Jean II */ - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlap_event[event]); - - ret = -EINVAL; - break; - } - return ret; -} - -/* - * Function irlap_state_pclose (event, skb, info) - * - * PCLOSE state - */ -static int irlap_state_pclose(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_UA_RSP: /* FALLTHROUGH */ - case RECV_DM_RSP: - del_timer(&self->final_timer); - - /* Set new link parameters */ - irlap_apply_default_connection_parameters(self); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - case FINAL_TIMER_EXPIRED: - if (self->retry_count < self->N3) { - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_disc_frame(self); - irlap_start_final_timer(self, self->final_timeout); - self->retry_count++; - /* Keep state */ - } 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; - default: - pr_debug("%s(), Unknown event %d\n", __func__, event); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_nrm_p (self, event, skb, info) - * - * NRM_P (Normal Response Mode as Primary), The primary station has given - * permissions to a secondary station to transmit IrLAP resonse frames - * (by sending a frame with the P bit set). The primary station will not - * transmit any frames and is expecting to receive frames only from the - * secondary to which transmission permissions has been given. - */ -static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - int ns_status; - int nr_status; - - switch (event) { - case RECV_I_RSP: /* Optimize for the common case */ - if (unlikely(skb->len <= LAP_ADDR_HEADER + LAP_CTRL_HEADER)) { - /* - * Input validation check: a stir4200/mcp2150 - * combination sometimes results in an empty i:rsp. - * This makes no sense; we can just ignore the frame - * and send an rr:cmd immediately. This happens before - * changing nr or ns so triggers a retransmit - */ - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, CMD_FRAME); - /* Keep state */ - break; - } - /* FIXME: must check for remote_busy below */ -#ifdef CONFIG_IRDA_FAST_RR - /* - * Reset the fast_RR so we can use the fast RR code with - * full speed the next time since peer may have more frames - * to transmitt - */ - self->fast_RR = FALSE; -#endif /* CONFIG_IRDA_FAST_RR */ - IRDA_ASSERT( info != NULL, return -1;); - - 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, cleanup our retry queue */ - irlap_update_nr_received(self, info->nr); - - /* - * Got expected NR, so reset the - * retry_count. This is not done by IrLAP spec, - * which is strange! - */ - self->retry_count = 0; - self->ack_required = TRUE; - - /* poll bit cleared? */ - if (!info->pf) { - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_P); - - irlap_data_indication(self, skb, FALSE); - } else { - /* No longer waiting for pf */ - del_timer(&self->final_timer); - - irlap_wait_min_turn_around(self, &self->qos_tx); - - /* Call higher layer *before* changing state - * to give them a chance to send data in the - * next LAP frame. - * Jean II */ - irlap_data_indication(self, skb, FALSE); - - /* XMIT states are the most dangerous state - * to be in, because user requests are - * processed directly and may change state. - * On the other hand, in NDM_P, those - * requests are queued and we will process - * them when we return to irlap_do_event(). - * Jean II - */ - irlap_next_state(self, LAP_XMIT_P); - - /* This is the last frame. - * Make sure it's always called in XMIT state. - * - Jean II */ - irlap_start_poll_timer(self, self->poll_timeout); - } - break; - - } - /* Unexpected next to send (Ns) */ - if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED)) - { - if (!info->pf) { - irlap_update_nr_received(self, info->nr); - - /* - * Wait until the last frame before doing - * anything - */ - - /* Keep state */ - irlap_next_state(self, LAP_NRM_P); - } else { - pr_debug("%s(), missing or duplicate frame!\n", - __func__); - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, CMD_FRAME); - - self->ack_required = FALSE; - - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_NRM_P); - } - break; - } - /* - * Unexpected next to receive (Nr) - */ - if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED)) - { - if (info->pf) { - self->vr = (self->vr + 1) % 8; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - /* Resend rejected frames */ - irlap_resend_rejected_frames(self, CMD_FRAME); - - self->ack_required = FALSE; - - /* Make sure we account for the time - * to transmit our frames. See comemnts - * in irlap_send_data_primary_poll(). - * Jean II */ - irlap_start_final_timer(self, 2 * self->final_timeout); - - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_P); - - irlap_data_indication(self, skb, FALSE); - } else { - /* - * Do not resend frames until the last - * frame has arrived from the other - * device. This is not documented in - * IrLAP!! - */ - self->vr = (self->vr + 1) % 8; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - self->ack_required = FALSE; - - /* Keep state, do not move this line!*/ - irlap_next_state(self, LAP_NRM_P); - - irlap_data_indication(self, skb, FALSE); - } - break; - } - /* - * Unexpected next to send (Ns) and next to receive (Nr) - * Not documented by IrLAP! - */ - if ((ns_status == NS_UNEXPECTED) && - (nr_status == NR_UNEXPECTED)) - { - pr_debug("%s(), unexpected nr and ns!\n", - __func__); - if (info->pf) { - /* Resend rejected frames */ - irlap_resend_rejected_frames(self, CMD_FRAME); - - /* Give peer some time to retransmit! - * But account for our own Tx. */ - irlap_start_final_timer(self, 2 * self->final_timeout); - - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_P); - } else { - /* Update Nr received */ - /* irlap_update_nr_received( info->nr); */ - - self->ack_required = FALSE; - } - break; - } - - /* - * Invalid NR or NS - */ - if ((nr_status == NR_INVALID) || (ns_status == NS_INVALID)) { - if (info->pf) { - del_timer(&self->final_timer); - - irlap_next_state(self, LAP_RESET_WAIT); - - irlap_disconnect_indication(self, LAP_RESET_INDICATION); - self->xmitflag = TRUE; - } else { - del_timer(&self->final_timer); - - irlap_disconnect_indication(self, LAP_RESET_INDICATION); - - self->xmitflag = FALSE; - } - break; - } - pr_debug("%s(), Not implemented!\n", __func__); - pr_debug("%s(), event=%s, ns_status=%d, nr_status=%d\n", - __func__, irlap_event[event], ns_status, nr_status); - break; - case RECV_UI_FRAME: - /* Poll bit cleared? */ - if (!info->pf) { - irlap_data_indication(self, skb, TRUE); - irlap_next_state(self, LAP_NRM_P); - } else { - del_timer(&self->final_timer); - irlap_data_indication(self, skb, TRUE); - irlap_next_state(self, LAP_XMIT_P); - pr_debug("%s: RECV_UI_FRAME: next state %s\n", - __func__, irlap_state[self->state]); - irlap_start_poll_timer(self, self->poll_timeout); - } - break; - case RECV_RR_RSP: - /* - * If you get a RR, the remote isn't busy anymore, - * no matter what the NR - */ - self->remote_busy = FALSE; - - /* Stop final timer */ - del_timer(&self->final_timer); - - /* - * Nr as expected? - */ - ret = irlap_validate_nr_received(self, info->nr); - if (ret == NR_EXPECTED) { - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - /* - * Got expected NR, so reset the retry_count. This - * is not done by the IrLAP standard , which is - * strange! DB. - */ - self->retry_count = 0; - irlap_wait_min_turn_around(self, &self->qos_tx); - - irlap_next_state(self, LAP_XMIT_P); - - /* Start poll timer */ - irlap_start_poll_timer(self, self->poll_timeout); - } else if (ret == NR_UNEXPECTED) { - IRDA_ASSERT(info != NULL, return -1;); - /* - * Unexpected nr! - */ - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - pr_debug("RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n", - self->retry_count, info->nr, self->va, - self->vs, self->vr); - - /* Resend rejected frames */ - irlap_resend_rejected_frames(self, CMD_FRAME); - irlap_start_final_timer(self, self->final_timeout * 2); - - irlap_next_state(self, LAP_NRM_P); - } else if (ret == NR_INVALID) { - pr_debug("%s(), Received RR with invalid nr !\n", - __func__); - - irlap_next_state(self, LAP_RESET_WAIT); - - irlap_disconnect_indication(self, LAP_RESET_INDICATION); - self->xmitflag = TRUE; - } - break; - case RECV_RNR_RSP: - IRDA_ASSERT(info != NULL, return -1;); - - /* Stop final timer */ - del_timer(&self->final_timer); - self->remote_busy = TRUE; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - irlap_next_state(self, LAP_XMIT_P); - - /* Start poll timer */ - irlap_start_poll_timer(self, self->poll_timeout); - break; - case RECV_FRMR_RSP: - del_timer(&self->final_timer); - self->xmitflag = TRUE; - irlap_next_state(self, LAP_RESET_WAIT); - irlap_reset_indication(self); - break; - case FINAL_TIMER_EXPIRED: - /* - * We are allowed to wait for additional 300 ms if - * final timer expires when we are in the middle - * of receiving a frame (page 45, IrLAP). Check that - * we only do this once for each frame. - */ - if (irda_device_is_receiving(self->netdev) && !self->add_wait) { - pr_debug("FINAL_TIMER_EXPIRED when receiving a frame! Waiting a little bit more!\n"); - irlap_start_final_timer(self, msecs_to_jiffies(300)); - - /* - * Don't allow this to happen one more time in a row, - * or else we can get a pretty tight loop here if - * if we only receive half a frame. DB. - */ - self->add_wait = TRUE; - break; - } - self->add_wait = FALSE; - - /* N2 is the disconnect timer. Until we reach it, we retry */ - if (self->retry_count < self->N2) { - if (skb_peek(&self->wx_list) == NULL) { - /* Retry sending the pf bit to the secondary */ - pr_debug("nrm_p: resending rr"); - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, CMD_FRAME); - } else { - pr_debug("nrm_p: resend frames"); - irlap_resend_rejected_frames(self, CMD_FRAME); - } - - irlap_start_final_timer(self, self->final_timeout); - self->retry_count++; - pr_debug("irlap_state_nrm_p: FINAL_TIMER_EXPIRED: retry_count=%d\n", - self->retry_count); - - /* Early warning event. I'm using a pretty liberal - * interpretation of the spec and generate an event - * every time the timer is multiple of N1 (and not - * only the first time). This allow application - * to know precisely if connectivity restart... - * Jean II */ - if((self->retry_count % self->N1) == 0) - irlap_status_indication(self, - STATUS_NO_ACTIVITY); - - /* Keep state */ - } 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_REJ_RSP: - 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, CMD_FRAME); - } else - irlap_resend_rejected_frames(self, CMD_FRAME); - irlap_start_final_timer(self, 2 * self->final_timeout); - break; - case RECV_SREJ_RSP: - 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, CMD_FRAME); - } else - irlap_resend_rejected_frame(self, CMD_FRAME); - irlap_start_final_timer(self, 2 * self->final_timeout); - break; - case RECV_RD_RSP: - pr_debug("%s(), RECV_RD_RSP\n", __func__); - - irlap_flush_all_queues(self); - irlap_next_state(self, LAP_XMIT_P); - /* Call back the LAP state machine to do a proper disconnect */ - irlap_disconnect_request(self); - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_reset_wait (event, skb, info) - * - * We have informed the service user of a reset condition, and is - * awaiting reset of disconnect request. - * - */ -static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - pr_debug("%s(), event = %s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case RESET_REQUEST: - if (self->xmitflag) { - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_snrm_frame(self, NULL); - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_RESET); - } else { - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_RESET); - } - break; - case DISCONNECT_REQUEST: - irlap_wait_min_turn_around( self, &self->qos_tx); - irlap_send_disc_frame( self); - irlap_flush_all_queues( self); - irlap_start_final_timer( self, self->final_timeout); - self->retry_count = 0; - irlap_next_state( self, LAP_PCLOSE); - break; - default: - pr_debug("%s(), Unknown event %s\n", __func__, - irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_reset (self, event, skb, info) - * - * We have sent a SNRM reset command to the peer layer, and is awaiting - * reply. - * - */ -static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - pr_debug("%s(), event = %s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case RECV_DISC_CMD: - del_timer(&self->final_timer); - - 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_UA_RSP: - del_timer(&self->final_timer); - - /* Initiate connection state */ - irlap_initiate_connection_state(self); - - irlap_reset_confirm(); - - self->remote_busy = FALSE; - - irlap_next_state(self, LAP_XMIT_P); - - irlap_start_poll_timer(self, self->poll_timeout); - - break; - case FINAL_TIMER_EXPIRED: - if (self->retry_count < 3) { - irlap_wait_min_turn_around(self, &self->qos_tx); - - IRDA_ASSERT(self->netdev != NULL, return -1;); - irlap_send_snrm_frame(self, self->qos_dev); - - self->retry_count++; /* Experimental!! */ - - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_RESET); - } else if (self->retry_count >= self->N3) { - 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_SNRM_CMD: - /* - * SNRM frame is not allowed to contain an I-field in this - * state - */ - if (!info) { - pr_debug("%s(), RECV_SNRM_CMD\n", __func__); - irlap_initiate_connection_state(self); - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_ua_response_frame(self, &self->qos_rx); - irlap_reset_confirm(); - irlap_start_wd_timer(self, self->wd_timeout); - irlap_next_state(self, LAP_NDM); - } else { - pr_debug("%s(), SNRM frame contained an I field!\n", - __func__); - } - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_xmit_s (event, skb, info) - * - * XMIT_S, The secondary station has been given the right to transmit, - * and we therefore do not expect to receive any transmissions from other - * stations. - */ -static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -ENODEV;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); - - switch (event) { - case SEND_I_CMD: - /* - * Send frame only if send window > 0 - */ - if ((self->window > 0) && (!self->remote_busy)) { - int nextfit; -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - struct sk_buff *skb_next; - - /* - * Same deal as in irlap_state_xmit_p(), so see - * the comments at that point. - * We are the secondary, so there are only subtle - * differences. - Jean II - */ - - /* Check if a subsequent skb exist and would fit in - * the current window (with respect to turnaround - * time). - Jean II */ - skb_next = skb_peek(&self->txq); - nextfit = ((skb_next != NULL) && - ((skb_next->len + skb->len) <= - self->bytes_left)); - - /* - * Test if we have transmitted more bytes over the - * link than its possible to do with the current - * speed and turn-around-time. - */ - if((!nextfit) && (skb->len > self->bytes_left)) { - pr_debug("%s(), Not allowed to transmit more bytes!\n", - __func__); - /* Requeue the skb */ - skb_queue_head(&self->txq, skb_get(skb)); - - /* - * Switch to NRM_S, this is only possible - * when we are in secondary mode, since we - * must be sure that we don't miss any RR - * frames - */ - self->window = self->window_size; - self->bytes_left = self->line_capacity; - irlap_start_wd_timer(self, self->wd_timeout); - - irlap_next_state(self, LAP_NRM_S); - /* Slight difference with primary : - * here we would wait for the other side to - * expire the turnaround. - Jean II */ - - return -EPROTO; /* Try again later */ - } - /* Subtract space used by this skb */ - self->bytes_left -= skb->len; -#else /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* Window has been adjusted for the max packet - * size, so much simpler... - Jean II */ - nextfit = !skb_queue_empty(&self->txq); -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* - * Send data with final bit cleared only if window > 1 - * and there is more frames to be sent - */ - if ((self->window > 1) && (nextfit)) { - irlap_send_data_secondary(self, skb); - irlap_next_state(self, LAP_XMIT_S); - } else { - irlap_send_data_secondary_final(self, skb); - irlap_next_state(self, LAP_NRM_S); - - /* - * Make sure state machine does not try to send - * any more frames - */ - ret = -EPROTO; - } - } else { - pr_debug("%s(), Unable to send!\n", __func__); - skb_queue_head(&self->txq, skb_get(skb)); - ret = -EPROTO; - } - break; - case DISCONNECT_REQUEST: - irlap_send_rd_frame(self); - irlap_flush_all_queues(self); - irlap_start_wd_timer(self, self->wd_timeout); - irlap_next_state(self, LAP_SCLOSE); - break; - case DATA_REQUEST: - /* Nothing to do, irlap_do_event() will send the packet - * when we return... - Jean II */ - break; - default: - pr_debug("%s(), Unknown event %s\n", __func__, - irlap_event[event]); - - ret = -EINVAL; - break; - } - 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; - - pr_debug("%s(), event=%s\n", __func__, 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 */ - pr_debug("%s(), event=%s nr=%d, vs=%d, ns=%d, vr=%d, pf=%d\n", - __func__, 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) { - pr_debug("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) { - pr_debug("NRM_S, NR_INVALID not implemented!\n"); - } - if (ret == NS_INVALID) { - pr_debug("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 { - pr_debug("%s(), invalid nr not implemented!\n", - __func__); - } - break; - case RECV_SNRM_CMD: - /* SNRM frame is not allowed to contain an I-field */ - if (!info) { - del_timer(&self->wd_timer); - pr_debug("%s(), received SNRM cmd\n", __func__); - irlap_next_state(self, LAP_RESET_CHECK); - - irlap_reset_indication(self); - } else { - pr_debug("%s(), SNRM frame contained an I-field!\n", - __func__); - - } - 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 - */ - pr_debug("%s(), retry_count = %d\n", __func__, - 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: - pr_debug("%s(), Unknown event %d, (%s)\n", __func__, - 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) -{ - 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 */ - } - - pr_debug("%s(), Unknown event %d, (%s)\n", __func__, - event, irlap_event[event]); - - 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; - - pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -ENODEV;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); - - switch (event) { - case RESET_RESPONSE: - irlap_send_ua_response_frame(self, &self->qos_rx); - irlap_initiate_connection_state(self); - irlap_start_wd_timer(self, WD_TIMEOUT); - irlap_flush_all_queues(self); - - irlap_next_state(self, LAP_NRM_S); - break; - case DISCONNECT_REQUEST: - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rd_frame(self); - irlap_start_wd_timer(self, WD_TIMEOUT); - irlap_next_state(self, LAP_SCLOSE); - break; - default: - pr_debug("%s(), Unknown event %d, (%s)\n", __func__, - event, irlap_event[event]); - - ret = -EINVAL; - break; - } - return ret; -} |