123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- /*********************************************************************
- *
- * Filename: irlan_client_event.c
- * Version: 0.9
- * Description: IrLAN client state machine
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun Dec 26 21:52:24 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- *
- * 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/skbuff.h>
- #include <net/irda/irda.h>
- #include <net/irda/timer.h>
- #include <net/irda/irmod.h>
- #include <net/irda/iriap.h>
- #include <net/irda/irlmp.h>
- #include <net/irda/irttp.h>
- #include <net/irda/irlan_common.h>
- #include <net/irda/irlan_client.h>
- #include <net/irda/irlan_event.h>
- static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_arb (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
- static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) =
- {
- irlan_client_state_idle,
- irlan_client_state_query,
- irlan_client_state_conn,
- irlan_client_state_info,
- irlan_client_state_media,
- irlan_client_state_open,
- irlan_client_state_wait,
- irlan_client_state_arb,
- irlan_client_state_data,
- irlan_client_state_close,
- irlan_client_state_sync
- };
- void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- (*state[ self->client.state]) (self, event, skb);
- }
- /*
- * Function irlan_client_state_idle (event, skb, info)
- *
- * IDLE, We are waiting for an indication that there is a provider
- * available.
- */
- static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
- switch (event) {
- case IRLAN_DISCOVERY_INDICATION:
- if (self->client.iriap) {
- net_warn_ratelimited("%s(), busy with a previous query\n",
- __func__);
- return -EBUSY;
- }
- self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- irlan_client_get_value_confirm);
- /* Get some values from peer IAS */
- irlan_next_client_state(self, IRLAN_QUERY);
- iriap_getvaluebyclass_request(self->client.iriap,
- self->saddr, self->daddr,
- "IrLAN", "IrDA:TinyTP:LsapSel");
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_query (event, skb, info)
- *
- * QUERY, We have queryed the remote IAS and is ready to connect
- * to provider, just waiting for the confirm.
- *
- */
- static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
- switch(event) {
- case IRLAN_IAS_PROVIDER_AVAIL:
- IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;);
- self->client.open_retries = 0;
- irttp_connect_request(self->client.tsap_ctrl,
- self->dtsap_sel_ctrl,
- self->saddr, self->daddr, NULL,
- IRLAN_MTU, NULL);
- irlan_next_client_state(self, IRLAN_CONN);
- break;
- case IRLAN_IAS_PROVIDER_NOT_AVAIL:
- pr_debug("%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__);
- irlan_next_client_state(self, IRLAN_IDLE);
- /* Give the client a kick! */
- if ((self->provider.access_type == ACCESS_PEER) &&
- (self->provider.state != IRLAN_IDLE))
- irlan_client_wakeup(self, self->saddr, self->daddr);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_conn (event, skb, info)
- *
- * CONN, We have connected to a provider but has not issued any
- * commands yet.
- *
- */
- static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- IRDA_ASSERT(self != NULL, return -1;);
- switch (event) {
- case IRLAN_CONNECT_COMPLETE:
- /* Send getinfo cmd */
- irlan_get_provider_info(self);
- irlan_next_client_state(self, IRLAN_INFO);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_info (self, event, skb, info)
- *
- * INFO, We have issued a GetInfo command and is awaiting a reply.
- */
- static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- IRDA_ASSERT(self != NULL, return -1;);
- switch (event) {
- case IRLAN_DATA_INDICATION:
- IRDA_ASSERT(skb != NULL, return -1;);
- irlan_client_parse_response(self, skb);
- irlan_next_client_state(self, IRLAN_MEDIA);
- irlan_get_media_char(self);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_media (self, event, skb, info)
- *
- * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a
- * reply.
- *
- */
- static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- IRDA_ASSERT(self != NULL, return -1;);
- switch(event) {
- case IRLAN_DATA_INDICATION:
- irlan_client_parse_response(self, skb);
- irlan_open_data_channel(self);
- irlan_next_client_state(self, IRLAN_OPEN);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_open (self, event, skb, info)
- *
- * OPEN, The irlan_client has issued a OpenData command and is awaiting a
- * reply
- *
- */
- static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- struct qos_info qos;
- IRDA_ASSERT(self != NULL, return -1;);
- switch(event) {
- case IRLAN_DATA_INDICATION:
- irlan_client_parse_response(self, skb);
- /*
- * Check if we have got the remote TSAP for data
- * communications
- */
- IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;);
- /* Check which access type we are dealing with */
- switch (self->client.access_type) {
- case ACCESS_PEER:
- if (self->provider.state == IRLAN_OPEN) {
- irlan_next_client_state(self, IRLAN_ARB);
- irlan_do_client_event(self, IRLAN_CHECK_CON_ARB,
- NULL);
- } else {
- irlan_next_client_state(self, IRLAN_WAIT);
- }
- break;
- case ACCESS_DIRECT:
- case ACCESS_HOSTED:
- qos.link_disc_time.bits = 0x01; /* 3 secs */
- irttp_connect_request(self->tsap_data,
- self->dtsap_sel_data,
- self->saddr, self->daddr, &qos,
- IRLAN_MTU, NULL);
- irlan_next_client_state(self, IRLAN_DATA);
- break;
- default:
- pr_debug("%s(), unknown access type!\n", __func__);
- break;
- }
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_wait (self, event, skb, info)
- *
- * WAIT, The irlan_client is waiting for the local provider to enter the
- * provider OPEN state.
- *
- */
- static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- IRDA_ASSERT(self != NULL, return -1;);
- switch(event) {
- case IRLAN_PROVIDER_SIGNAL:
- irlan_next_client_state(self, IRLAN_ARB);
- irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- struct qos_info qos;
- IRDA_ASSERT(self != NULL, return -1;);
- switch(event) {
- case IRLAN_CHECK_CON_ARB:
- if (self->client.recv_arb_val == self->provider.send_arb_val) {
- irlan_next_client_state(self, IRLAN_CLOSE);
- irlan_close_data_channel(self);
- } else if (self->client.recv_arb_val <
- self->provider.send_arb_val)
- {
- qos.link_disc_time.bits = 0x01; /* 3 secs */
- irlan_next_client_state(self, IRLAN_DATA);
- irttp_connect_request(self->tsap_data,
- self->dtsap_sel_data,
- self->saddr, self->daddr, &qos,
- IRLAN_MTU, NULL);
- } else if (self->client.recv_arb_val >
- self->provider.send_arb_val)
- {
- pr_debug("%s(), lost the battle :-(\n", __func__);
- }
- break;
- case IRLAN_DATA_CONNECT_INDICATION:
- irlan_next_client_state(self, IRLAN_DATA);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_data (self, event, skb, info)
- *
- * DATA, The data channel is connected, allowing data transfers between
- * the local and remote machines.
- *
- */
- static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
- switch(event) {
- case IRLAN_DATA_INDICATION:
- irlan_client_parse_response(self, skb);
- break;
- case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_close (self, event, skb, info)
- *
- *
- *
- */
- static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
- /*
- * Function irlan_client_state_sync (self, event, skb, info)
- *
- *
- *
- */
- static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
- {
- if (skb)
- dev_kfree_skb(skb);
- return 0;
- }
|