Path: blob/master/net/irda/irlan/irlan_client_event.c
17602 views
/*********************************************************************1*2* Filename: irlan_client_event.c3* Version: 0.94* Description: IrLAN client state machine5* Status: Experimental.6* Author: Dag Brattli <[email protected]>7* Created at: Sun Aug 31 20:14:37 19978* Modified at: Sun Dec 26 21:52:24 19999* Modified by: Dag Brattli <[email protected]>10*11* Copyright (c) 1998-1999 Dag Brattli <[email protected]>,12* All Rights Reserved.13*14* This program is free software; you can redistribute it and/or15* modify it under the terms of the GNU General Public License as16* published by the Free Software Foundation; either version 2 of17* the License, or (at your option) any later version.18*19* Neither Dag Brattli nor University of Tromsø admit liability nor20* provide warranty for any of this software. This material is21* provided "AS-IS" and at no charge.22*23********************************************************************/2425#include <linux/skbuff.h>2627#include <net/irda/irda.h>28#include <net/irda/timer.h>29#include <net/irda/irmod.h>30#include <net/irda/iriap.h>31#include <net/irda/irlmp.h>32#include <net/irda/irttp.h>3334#include <net/irda/irlan_common.h>35#include <net/irda/irlan_client.h>36#include <net/irda/irlan_event.h>3738static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event,39struct sk_buff *skb);40static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,41struct sk_buff *skb);42static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event,43struct sk_buff *skb);44static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event,45struct sk_buff *skb);46static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,47struct sk_buff *skb);48static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event,49struct sk_buff *skb);50static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event,51struct sk_buff *skb);52static int irlan_client_state_arb (struct irlan_cb *self, IRLAN_EVENT event,53struct sk_buff *skb);54static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event,55struct sk_buff *skb);56static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,57struct sk_buff *skb);58static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event,59struct sk_buff *skb);6061static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) =62{63irlan_client_state_idle,64irlan_client_state_query,65irlan_client_state_conn,66irlan_client_state_info,67irlan_client_state_media,68irlan_client_state_open,69irlan_client_state_wait,70irlan_client_state_arb,71irlan_client_state_data,72irlan_client_state_close,73irlan_client_state_sync74};7576void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,77struct sk_buff *skb)78{79IRDA_ASSERT(self != NULL, return;);80IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);8182(*state[ self->client.state]) (self, event, skb);83}8485/*86* Function irlan_client_state_idle (event, skb, info)87*88* IDLE, We are waiting for an indication that there is a provider89* available.90*/91static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,92struct sk_buff *skb)93{94IRDA_DEBUG(4, "%s()\n", __func__ );9596IRDA_ASSERT(self != NULL, return -1;);97IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);9899switch (event) {100case IRLAN_DISCOVERY_INDICATION:101if (self->client.iriap) {102IRDA_WARNING("%s(), busy with a previous query\n",103__func__);104return -EBUSY;105}106107self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,108irlan_client_get_value_confirm);109/* Get some values from peer IAS */110irlan_next_client_state(self, IRLAN_QUERY);111iriap_getvaluebyclass_request(self->client.iriap,112self->saddr, self->daddr,113"IrLAN", "IrDA:TinyTP:LsapSel");114break;115case IRLAN_WATCHDOG_TIMEOUT:116IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );117break;118default:119IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event);120break;121}122if (skb)123dev_kfree_skb(skb);124125return 0;126}127128/*129* Function irlan_client_state_query (event, skb, info)130*131* QUERY, We have queryed the remote IAS and is ready to connect132* to provider, just waiting for the confirm.133*134*/135static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,136struct sk_buff *skb)137{138IRDA_DEBUG(4, "%s()\n", __func__ );139140IRDA_ASSERT(self != NULL, return -1;);141IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);142143switch(event) {144case IRLAN_IAS_PROVIDER_AVAIL:145IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;);146147self->client.open_retries = 0;148149irttp_connect_request(self->client.tsap_ctrl,150self->dtsap_sel_ctrl,151self->saddr, self->daddr, NULL,152IRLAN_MTU, NULL);153irlan_next_client_state(self, IRLAN_CONN);154break;155case IRLAN_IAS_PROVIDER_NOT_AVAIL:156IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__ );157irlan_next_client_state(self, IRLAN_IDLE);158159/* Give the client a kick! */160if ((self->provider.access_type == ACCESS_PEER) &&161(self->provider.state != IRLAN_IDLE))162irlan_client_wakeup(self, self->saddr, self->daddr);163break;164case IRLAN_LMP_DISCONNECT:165case IRLAN_LAP_DISCONNECT:166irlan_next_client_state(self, IRLAN_IDLE);167break;168case IRLAN_WATCHDOG_TIMEOUT:169IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );170break;171default:172IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);173break;174}175if (skb)176dev_kfree_skb(skb);177178return 0;179}180181/*182* Function irlan_client_state_conn (event, skb, info)183*184* CONN, We have connected to a provider but has not issued any185* commands yet.186*187*/188static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,189struct sk_buff *skb)190{191IRDA_DEBUG(4, "%s()\n", __func__ );192193IRDA_ASSERT(self != NULL, return -1;);194195switch (event) {196case IRLAN_CONNECT_COMPLETE:197/* Send getinfo cmd */198irlan_get_provider_info(self);199irlan_next_client_state(self, IRLAN_INFO);200break;201case IRLAN_LMP_DISCONNECT:202case IRLAN_LAP_DISCONNECT:203irlan_next_client_state(self, IRLAN_IDLE);204break;205case IRLAN_WATCHDOG_TIMEOUT:206IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );207break;208default:209IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);210break;211}212if (skb)213dev_kfree_skb(skb);214215return 0;216}217218/*219* Function irlan_client_state_info (self, event, skb, info)220*221* INFO, We have issued a GetInfo command and is awaiting a reply.222*/223static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,224struct sk_buff *skb)225{226IRDA_DEBUG(4, "%s()\n", __func__ );227228IRDA_ASSERT(self != NULL, return -1;);229230switch (event) {231case IRLAN_DATA_INDICATION:232IRDA_ASSERT(skb != NULL, return -1;);233234irlan_client_parse_response(self, skb);235236irlan_next_client_state(self, IRLAN_MEDIA);237238irlan_get_media_char(self);239break;240241case IRLAN_LMP_DISCONNECT:242case IRLAN_LAP_DISCONNECT:243irlan_next_client_state(self, IRLAN_IDLE);244break;245case IRLAN_WATCHDOG_TIMEOUT:246IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );247break;248default:249IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);250break;251}252if (skb)253dev_kfree_skb(skb);254255return 0;256}257258/*259* Function irlan_client_state_media (self, event, skb, info)260*261* MEDIA, The irlan_client has issued a GetMedia command and is awaiting a262* reply.263*264*/265static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,266struct sk_buff *skb)267{268IRDA_DEBUG(4, "%s()\n", __func__ );269270IRDA_ASSERT(self != NULL, return -1;);271272switch(event) {273case IRLAN_DATA_INDICATION:274irlan_client_parse_response(self, skb);275irlan_open_data_channel(self);276irlan_next_client_state(self, IRLAN_OPEN);277break;278case IRLAN_LMP_DISCONNECT:279case IRLAN_LAP_DISCONNECT:280irlan_next_client_state(self, IRLAN_IDLE);281break;282case IRLAN_WATCHDOG_TIMEOUT:283IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );284break;285default:286IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);287break;288}289if (skb)290dev_kfree_skb(skb);291292return 0;293}294295/*296* Function irlan_client_state_open (self, event, skb, info)297*298* OPEN, The irlan_client has issued a OpenData command and is awaiting a299* reply300*301*/302static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,303struct sk_buff *skb)304{305struct qos_info qos;306307IRDA_DEBUG(4, "%s()\n", __func__ );308309IRDA_ASSERT(self != NULL, return -1;);310311switch(event) {312case IRLAN_DATA_INDICATION:313irlan_client_parse_response(self, skb);314315/*316* Check if we have got the remote TSAP for data317* communications318*/319IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;);320321/* Check which access type we are dealing with */322switch (self->client.access_type) {323case ACCESS_PEER:324if (self->provider.state == IRLAN_OPEN) {325326irlan_next_client_state(self, IRLAN_ARB);327irlan_do_client_event(self, IRLAN_CHECK_CON_ARB,328NULL);329} else {330331irlan_next_client_state(self, IRLAN_WAIT);332}333break;334case ACCESS_DIRECT:335case ACCESS_HOSTED:336qos.link_disc_time.bits = 0x01; /* 3 secs */337338irttp_connect_request(self->tsap_data,339self->dtsap_sel_data,340self->saddr, self->daddr, &qos,341IRLAN_MTU, NULL);342343irlan_next_client_state(self, IRLAN_DATA);344break;345default:346IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ );347break;348}349break;350case IRLAN_LMP_DISCONNECT:351case IRLAN_LAP_DISCONNECT:352irlan_next_client_state(self, IRLAN_IDLE);353break;354case IRLAN_WATCHDOG_TIMEOUT:355IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );356break;357default:358IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);359break;360}361362if (skb)363dev_kfree_skb(skb);364365return 0;366}367368/*369* Function irlan_client_state_wait (self, event, skb, info)370*371* WAIT, The irlan_client is waiting for the local provider to enter the372* provider OPEN state.373*374*/375static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,376struct sk_buff *skb)377{378IRDA_DEBUG(4, "%s()\n", __func__ );379380IRDA_ASSERT(self != NULL, return -1;);381382switch(event) {383case IRLAN_PROVIDER_SIGNAL:384irlan_next_client_state(self, IRLAN_ARB);385irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL);386break;387case IRLAN_LMP_DISCONNECT:388case IRLAN_LAP_DISCONNECT:389irlan_next_client_state(self, IRLAN_IDLE);390break;391case IRLAN_WATCHDOG_TIMEOUT:392IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );393break;394default:395IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);396break;397}398if (skb)399dev_kfree_skb(skb);400401return 0;402}403404static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,405struct sk_buff *skb)406{407struct qos_info qos;408409IRDA_DEBUG(2, "%s()\n", __func__ );410411IRDA_ASSERT(self != NULL, return -1;);412413switch(event) {414case IRLAN_CHECK_CON_ARB:415if (self->client.recv_arb_val == self->provider.send_arb_val) {416irlan_next_client_state(self, IRLAN_CLOSE);417irlan_close_data_channel(self);418} else if (self->client.recv_arb_val <419self->provider.send_arb_val)420{421qos.link_disc_time.bits = 0x01; /* 3 secs */422423irlan_next_client_state(self, IRLAN_DATA);424irttp_connect_request(self->tsap_data,425self->dtsap_sel_data,426self->saddr, self->daddr, &qos,427IRLAN_MTU, NULL);428} else if (self->client.recv_arb_val >429self->provider.send_arb_val)430{431IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __func__ );432}433break;434case IRLAN_DATA_CONNECT_INDICATION:435irlan_next_client_state(self, IRLAN_DATA);436break;437case IRLAN_LMP_DISCONNECT:438case IRLAN_LAP_DISCONNECT:439irlan_next_client_state(self, IRLAN_IDLE);440break;441case IRLAN_WATCHDOG_TIMEOUT:442IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );443break;444default:445IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);446break;447}448if (skb)449dev_kfree_skb(skb);450451return 0;452}453454/*455* Function irlan_client_state_data (self, event, skb, info)456*457* DATA, The data channel is connected, allowing data transfers between458* the local and remote machines.459*460*/461static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,462struct sk_buff *skb)463{464IRDA_DEBUG(4, "%s()\n", __func__ );465466IRDA_ASSERT(self != NULL, return -1;);467IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);468469switch(event) {470case IRLAN_DATA_INDICATION:471irlan_client_parse_response(self, skb);472break;473case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */474case IRLAN_LAP_DISCONNECT:475irlan_next_client_state(self, IRLAN_IDLE);476break;477default:478IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);479break;480}481if (skb)482dev_kfree_skb(skb);483484return 0;485}486487/*488* Function irlan_client_state_close (self, event, skb, info)489*490*491*492*/493static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,494struct sk_buff *skb)495{496IRDA_DEBUG(2, "%s()\n", __func__ );497498if (skb)499dev_kfree_skb(skb);500501return 0;502}503504/*505* Function irlan_client_state_sync (self, event, skb, info)506*507*508*509*/510static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,511struct sk_buff *skb)512{513IRDA_DEBUG(2, "%s()\n", __func__ );514515if (skb)516dev_kfree_skb(skb);517518return 0;519}520521522523524525526527528529530531532533534535