linux/net/irda/ircomm/ircomm_event.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      ircomm_event.c
   4 * Version:       1.0
   5 * Description:   IrCOMM layer state machine
   6 * Status:        Stable
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Sun Jun  6 20:33:11 1999
   9 * Modified at:   Sun Dec 12 13:44:32 1999
  10 * Modified by:   Dag Brattli <dagb@cs.uit.no>
  11 *
  12 *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
  13 *
  14 *     This program is free software; you can redistribute it and/or
  15 *     modify it under the terms of the GNU General Public License as
  16 *     published by the Free Software Foundation; either version 2 of
  17 *     the License, or (at your option) any later version.
  18 *
  19 *     This program is distributed in the hope that it will be useful,
  20 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22 *     GNU General Public License for more details.
  23 *
  24 *     You should have received a copy of the GNU General Public License
  25 *     along with this program; if not, see <http://www.gnu.org/licenses/>.
  26 *
  27 ********************************************************************/
  28
  29#include <linux/proc_fs.h>
  30#include <linux/init.h>
  31
  32#include <net/irda/irda.h>
  33#include <net/irda/irlmp.h>
  34#include <net/irda/iriap.h>
  35#include <net/irda/irttp.h>
  36#include <net/irda/irias_object.h>
  37
  38#include <net/irda/ircomm_core.h>
  39#include <net/irda/ircomm_event.h>
  40
  41static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
  42                             struct sk_buff *skb, struct ircomm_info *info);
  43static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
  44                              struct sk_buff *skb, struct ircomm_info *info);
  45static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
  46                              struct sk_buff *skb, struct ircomm_info *info);
  47static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
  48                             struct sk_buff *skb, struct ircomm_info *info);
  49
  50const char *const ircomm_state[] = {
  51        "IRCOMM_IDLE",
  52        "IRCOMM_WAITI",
  53        "IRCOMM_WAITR",
  54        "IRCOMM_CONN",
  55};
  56
  57static const char *const ircomm_event[] __maybe_unused = {
  58        "IRCOMM_CONNECT_REQUEST",
  59        "IRCOMM_CONNECT_RESPONSE",
  60        "IRCOMM_TTP_CONNECT_INDICATION",
  61        "IRCOMM_LMP_CONNECT_INDICATION",
  62        "IRCOMM_TTP_CONNECT_CONFIRM",
  63        "IRCOMM_LMP_CONNECT_CONFIRM",
  64
  65        "IRCOMM_LMP_DISCONNECT_INDICATION",
  66        "IRCOMM_TTP_DISCONNECT_INDICATION",
  67        "IRCOMM_DISCONNECT_REQUEST",
  68
  69        "IRCOMM_TTP_DATA_INDICATION",
  70        "IRCOMM_LMP_DATA_INDICATION",
  71        "IRCOMM_DATA_REQUEST",
  72        "IRCOMM_CONTROL_REQUEST",
  73        "IRCOMM_CONTROL_INDICATION",
  74};
  75
  76static int (*state[])(struct ircomm_cb *self, IRCOMM_EVENT event,
  77                      struct sk_buff *skb, struct ircomm_info *info) =
  78{
  79        ircomm_state_idle,
  80        ircomm_state_waiti,
  81        ircomm_state_waitr,
  82        ircomm_state_conn,
  83};
  84
  85/*
  86 * Function ircomm_state_idle (self, event, skb)
  87 *
  88 *    IrCOMM is currently idle
  89 *
  90 */
  91static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
  92                             struct sk_buff *skb, struct ircomm_info *info)
  93{
  94        int ret = 0;
  95
  96        switch (event) {
  97        case IRCOMM_CONNECT_REQUEST:
  98                ircomm_next_state(self, IRCOMM_WAITI);
  99                ret = self->issue.connect_request(self, skb, info);
 100                break;
 101        case IRCOMM_TTP_CONNECT_INDICATION:
 102        case IRCOMM_LMP_CONNECT_INDICATION:
 103                ircomm_next_state(self, IRCOMM_WAITR);
 104                ircomm_connect_indication(self, skb, info);
 105                break;
 106        default:
 107                pr_debug("%s(), unknown event: %s\n", __func__ ,
 108                         ircomm_event[event]);
 109                ret = -EINVAL;
 110        }
 111        return ret;
 112}
 113
 114/*
 115 * Function ircomm_state_waiti (self, event, skb)
 116 *
 117 *    The IrCOMM user has requested an IrCOMM connection to the remote
 118 *    device and is awaiting confirmation
 119 */
 120static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
 121                              struct sk_buff *skb, struct ircomm_info *info)
 122{
 123        int ret = 0;
 124
 125        switch (event) {
 126        case IRCOMM_TTP_CONNECT_CONFIRM:
 127        case IRCOMM_LMP_CONNECT_CONFIRM:
 128                ircomm_next_state(self, IRCOMM_CONN);
 129                ircomm_connect_confirm(self, skb, info);
 130                break;
 131        case IRCOMM_TTP_DISCONNECT_INDICATION:
 132        case IRCOMM_LMP_DISCONNECT_INDICATION:
 133                ircomm_next_state(self, IRCOMM_IDLE);
 134                ircomm_disconnect_indication(self, skb, info);
 135                break;
 136        default:
 137                pr_debug("%s(), unknown event: %s\n", __func__ ,
 138                         ircomm_event[event]);
 139                ret = -EINVAL;
 140        }
 141        return ret;
 142}
 143
 144/*
 145 * Function ircomm_state_waitr (self, event, skb)
 146 *
 147 *    IrCOMM has received an incoming connection request and is awaiting
 148 *    response from the user
 149 */
 150static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
 151                              struct sk_buff *skb, struct ircomm_info *info)
 152{
 153        int ret = 0;
 154
 155        switch (event) {
 156        case IRCOMM_CONNECT_RESPONSE:
 157                ircomm_next_state(self, IRCOMM_CONN);
 158                ret = self->issue.connect_response(self, skb);
 159                break;
 160        case IRCOMM_DISCONNECT_REQUEST:
 161                ircomm_next_state(self, IRCOMM_IDLE);
 162                ret = self->issue.disconnect_request(self, skb, info);
 163                break;
 164        case IRCOMM_TTP_DISCONNECT_INDICATION:
 165        case IRCOMM_LMP_DISCONNECT_INDICATION:
 166                ircomm_next_state(self, IRCOMM_IDLE);
 167                ircomm_disconnect_indication(self, skb, info);
 168                break;
 169        default:
 170                pr_debug("%s(), unknown event = %s\n", __func__ ,
 171                         ircomm_event[event]);
 172                ret = -EINVAL;
 173        }
 174        return ret;
 175}
 176
 177/*
 178 * Function ircomm_state_conn (self, event, skb)
 179 *
 180 *    IrCOMM is connected to the peer IrCOMM device
 181 *
 182 */
 183static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
 184                             struct sk_buff *skb, struct ircomm_info *info)
 185{
 186        int ret = 0;
 187
 188        switch (event) {
 189        case IRCOMM_DATA_REQUEST:
 190                ret = self->issue.data_request(self, skb, 0);
 191                break;
 192        case IRCOMM_TTP_DATA_INDICATION:
 193                ircomm_process_data(self, skb);
 194                break;
 195        case IRCOMM_LMP_DATA_INDICATION:
 196                ircomm_data_indication(self, skb);
 197                break;
 198        case IRCOMM_CONTROL_REQUEST:
 199                /* Just send a separate frame for now */
 200                ret = self->issue.data_request(self, skb, skb->len);
 201                break;
 202        case IRCOMM_TTP_DISCONNECT_INDICATION:
 203        case IRCOMM_LMP_DISCONNECT_INDICATION:
 204                ircomm_next_state(self, IRCOMM_IDLE);
 205                ircomm_disconnect_indication(self, skb, info);
 206                break;
 207        case IRCOMM_DISCONNECT_REQUEST:
 208                ircomm_next_state(self, IRCOMM_IDLE);
 209                ret = self->issue.disconnect_request(self, skb, info);
 210                break;
 211        default:
 212                pr_debug("%s(), unknown event = %s\n", __func__ ,
 213                         ircomm_event[event]);
 214                ret = -EINVAL;
 215        }
 216        return ret;
 217}
 218
 219/*
 220 * Function ircomm_do_event (self, event, skb)
 221 *
 222 *    Process event
 223 *
 224 */
 225int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
 226                    struct sk_buff *skb, struct ircomm_info *info)
 227{
 228        pr_debug("%s: state=%s, event=%s\n", __func__ ,
 229                 ircomm_state[self->state], ircomm_event[event]);
 230
 231        return (*state[self->state])(self, event, skb, info);
 232}
 233
 234/*
 235 * Function ircomm_next_state (self, state)
 236 *
 237 *    Switch state
 238 *
 239 */
 240void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state)
 241{
 242        self->state = state;
 243
 244        pr_debug("%s: next state=%s, service type=%d\n", __func__ ,
 245                 ircomm_state[self->state], self->service_type);
 246}
 247