linux/net/irda/ircomm/ircomm_ttp.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      ircomm_ttp.c
   4 * Version:       1.0
   5 * Description:   Interface between IrCOMM and IrTTP
   6 * Status:        Stable
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Sun Jun  6 20:48:27 1999
   9 * Modified at:   Mon Dec 13 11:35:13 1999
  10 * Modified by:   Dag Brattli <dagb@cs.uit.no>
  11 *
  12 *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
  13 *     Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
  14 *
  15 *     This program is free software; you can redistribute it and/or
  16 *     modify it under the terms of the GNU General Public License as
  17 *     published by the Free Software Foundation; either version 2 of
  18 *     the License, or (at your option) any later version.
  19 *
  20 *     This program is distributed in the hope that it will be useful,
  21 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  22 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23 *     GNU General Public License for more details.
  24 *
  25 *     You should have received a copy of the GNU General Public License
  26 *     along with this program; if not, write to the Free Software
  27 *     Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  28 *     MA 02111-1307 USA
  29 *
  30 ********************************************************************/
  31
  32#include <linux/init.h>
  33
  34#include <net/irda/irda.h>
  35#include <net/irda/irlmp.h>
  36#include <net/irda/iriap.h>
  37#include <net/irda/irttp.h>
  38
  39#include <net/irda/ircomm_event.h>
  40#include <net/irda/ircomm_ttp.h>
  41
  42static int ircomm_ttp_data_indication(void *instance, void *sap,
  43                                      struct sk_buff *skb);
  44static void ircomm_ttp_connect_confirm(void *instance, void *sap,
  45                                       struct qos_info *qos,
  46                                       __u32 max_sdu_size,
  47                                       __u8 max_header_size,
  48                                       struct sk_buff *skb);
  49static void ircomm_ttp_connect_indication(void *instance, void *sap,
  50                                          struct qos_info *qos,
  51                                          __u32 max_sdu_size,
  52                                          __u8 max_header_size,
  53                                          struct sk_buff *skb);
  54static void ircomm_ttp_flow_indication(void *instance, void *sap,
  55                                       LOCAL_FLOW cmd);
  56static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
  57                                             LM_REASON reason,
  58                                             struct sk_buff *skb);
  59static int ircomm_ttp_data_request(struct ircomm_cb *self,
  60                                   struct sk_buff *skb,
  61                                   int clen);
  62static int ircomm_ttp_connect_request(struct ircomm_cb *self,
  63                                      struct sk_buff *userdata,
  64                                      struct ircomm_info *info);
  65static int ircomm_ttp_connect_response(struct ircomm_cb *self,
  66                                       struct sk_buff *userdata);
  67static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
  68                                         struct sk_buff *userdata,
  69                                         struct ircomm_info *info);
  70
  71/*
  72 * Function ircomm_open_tsap (self)
  73 *
  74 *
  75 *
  76 */
  77int ircomm_open_tsap(struct ircomm_cb *self)
  78{
  79        notify_t notify;
  80
  81        IRDA_DEBUG(4, "%s()\n", __func__ );
  82
  83        /* Register callbacks */
  84        irda_notify_init(&notify);
  85        notify.data_indication       = ircomm_ttp_data_indication;
  86        notify.connect_confirm       = ircomm_ttp_connect_confirm;
  87        notify.connect_indication    = ircomm_ttp_connect_indication;
  88        notify.flow_indication       = ircomm_ttp_flow_indication;
  89        notify.disconnect_indication = ircomm_ttp_disconnect_indication;
  90        notify.instance = self;
  91        strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
  92
  93        self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
  94                                     &notify);
  95        if (!self->tsap) {
  96                IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __func__ );
  97                return -1;
  98        }
  99        self->slsap_sel = self->tsap->stsap_sel;
 100
 101        /*
 102         *  Initialize the call-table for issuing commands
 103         */
 104        self->issue.data_request       = ircomm_ttp_data_request;
 105        self->issue.connect_request    = ircomm_ttp_connect_request;
 106        self->issue.connect_response   = ircomm_ttp_connect_response;
 107        self->issue.disconnect_request = ircomm_ttp_disconnect_request;
 108
 109        return 0;
 110}
 111
 112/*
 113 * Function ircomm_ttp_connect_request (self, userdata)
 114 *
 115 *
 116 *
 117 */
 118static int ircomm_ttp_connect_request(struct ircomm_cb *self,
 119                                      struct sk_buff *userdata,
 120                                      struct ircomm_info *info)
 121{
 122        int ret = 0;
 123
 124        IRDA_DEBUG(4, "%s()\n", __func__ );
 125
 126        /* Don't forget to refcount it - should be NULL anyway */
 127        if(userdata)
 128                skb_get(userdata);
 129
 130        ret = irttp_connect_request(self->tsap, info->dlsap_sel,
 131                                    info->saddr, info->daddr, NULL,
 132                                    TTP_SAR_DISABLE, userdata);
 133
 134        return ret;
 135}
 136
 137/*
 138 * Function ircomm_ttp_connect_response (self, skb)
 139 *
 140 *
 141 *
 142 */
 143static int ircomm_ttp_connect_response(struct ircomm_cb *self,
 144                                       struct sk_buff *userdata)
 145{
 146        int ret;
 147
 148        IRDA_DEBUG(4, "%s()\n", __func__ );
 149
 150        /* Don't forget to refcount it - should be NULL anyway */
 151        if(userdata)
 152                skb_get(userdata);
 153
 154        ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata);
 155
 156        return ret;
 157}
 158
 159/*
 160 * Function ircomm_ttp_data_request (self, userdata)
 161 *
 162 *    Send IrCOMM data to IrTTP layer. Currently we do not try to combine
 163 *    control data with pure data, so they will be sent as separate frames.
 164 *    Should not be a big problem though, since control frames are rare. But
 165 *    some of them are sent after connection establishment, so this can
 166 *    increase the latency a bit.
 167 */
 168static int ircomm_ttp_data_request(struct ircomm_cb *self,
 169                                   struct sk_buff *skb,
 170                                   int clen)
 171{
 172        int ret;
 173
 174        IRDA_ASSERT(skb != NULL, return -1;);
 175
 176        IRDA_DEBUG(2, "%s(), clen=%d\n", __func__ , clen);
 177
 178        /*
 179         * Insert clen field, currently we either send data only, or control
 180         * only frames, to make things easier and avoid queueing
 181         */
 182        IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
 183
 184        /* Don't forget to refcount it - see ircomm_tty_do_softint() */
 185        skb_get(skb);
 186
 187        skb_push(skb, IRCOMM_HEADER_SIZE);
 188
 189        skb->data[0] = clen;
 190
 191        ret = irttp_data_request(self->tsap, skb);
 192        if (ret) {
 193                IRDA_ERROR("%s(), failed\n", __func__);
 194                /* irttp_data_request already free the packet */
 195        }
 196
 197        return ret;
 198}
 199
 200/*
 201 * Function ircomm_ttp_data_indication (instance, sap, skb)
 202 *
 203 *    Incoming data
 204 *
 205 */
 206static int ircomm_ttp_data_indication(void *instance, void *sap,
 207                                      struct sk_buff *skb)
 208{
 209        struct ircomm_cb *self = (struct ircomm_cb *) instance;
 210
 211        IRDA_DEBUG(4, "%s()\n", __func__ );
 212
 213        IRDA_ASSERT(self != NULL, return -1;);
 214        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 215        IRDA_ASSERT(skb != NULL, return -1;);
 216
 217        ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
 218
 219        /* Drop reference count - see ircomm_tty_data_indication(). */
 220        dev_kfree_skb(skb);
 221
 222        return 0;
 223}
 224
 225static void ircomm_ttp_connect_confirm(void *instance, void *sap,
 226                                       struct qos_info *qos,
 227                                       __u32 max_sdu_size,
 228                                       __u8 max_header_size,
 229                                       struct sk_buff *skb)
 230{
 231        struct ircomm_cb *self = (struct ircomm_cb *) instance;
 232        struct ircomm_info info;
 233
 234        IRDA_DEBUG(4, "%s()\n", __func__ );
 235
 236        IRDA_ASSERT(self != NULL, return;);
 237        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 238        IRDA_ASSERT(skb != NULL, return;);
 239        IRDA_ASSERT(qos != NULL, goto out;);
 240
 241        if (max_sdu_size != TTP_SAR_DISABLE) {
 242                IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
 243                           __func__);
 244                goto out;
 245        }
 246
 247        info.max_data_size = irttp_get_max_seg_size(self->tsap)
 248                - IRCOMM_HEADER_SIZE;
 249        info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
 250        info.qos = qos;
 251
 252        ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
 253
 254out:
 255        /* Drop reference count - see ircomm_tty_connect_confirm(). */
 256        dev_kfree_skb(skb);
 257}
 258
 259/*
 260 * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size,
 261 *                                         max_header_size, skb)
 262 *
 263 *
 264 *
 265 */
 266static void ircomm_ttp_connect_indication(void *instance, void *sap,
 267                                          struct qos_info *qos,
 268                                          __u32 max_sdu_size,
 269                                          __u8 max_header_size,
 270                                          struct sk_buff *skb)
 271{
 272        struct ircomm_cb *self = (struct ircomm_cb *)instance;
 273        struct ircomm_info info;
 274
 275        IRDA_DEBUG(4, "%s()\n", __func__ );
 276
 277        IRDA_ASSERT(self != NULL, return;);
 278        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 279        IRDA_ASSERT(skb != NULL, return;);
 280        IRDA_ASSERT(qos != NULL, goto out;);
 281
 282        if (max_sdu_size != TTP_SAR_DISABLE) {
 283                IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
 284                           __func__);
 285                goto out;
 286        }
 287
 288        info.max_data_size = irttp_get_max_seg_size(self->tsap)
 289                - IRCOMM_HEADER_SIZE;
 290        info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
 291        info.qos = qos;
 292
 293        ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
 294
 295out:
 296        /* Drop reference count - see ircomm_tty_connect_indication(). */
 297        dev_kfree_skb(skb);
 298}
 299
 300/*
 301 * Function ircomm_ttp_disconnect_request (self, userdata, info)
 302 *
 303 *
 304 *
 305 */
 306static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
 307                                         struct sk_buff *userdata,
 308                                         struct ircomm_info *info)
 309{
 310        int ret;
 311
 312        /* Don't forget to refcount it - should be NULL anyway */
 313        if(userdata)
 314                skb_get(userdata);
 315
 316        ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
 317
 318        return ret;
 319}
 320
 321/*
 322 * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb)
 323 *
 324 *
 325 *
 326 */
 327static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
 328                                             LM_REASON reason,
 329                                             struct sk_buff *skb)
 330{
 331        struct ircomm_cb *self = (struct ircomm_cb *) instance;
 332        struct ircomm_info info;
 333
 334        IRDA_DEBUG(2, "%s()\n", __func__ );
 335
 336        IRDA_ASSERT(self != NULL, return;);
 337        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 338
 339        info.reason = reason;
 340
 341        ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
 342
 343        /* Drop reference count - see ircomm_tty_disconnect_indication(). */
 344        if(skb)
 345                dev_kfree_skb(skb);
 346}
 347
 348/*
 349 * Function ircomm_ttp_flow_indication (instance, sap, cmd)
 350 *
 351 *    Layer below is telling us to start or stop the flow of data
 352 *
 353 */
 354static void ircomm_ttp_flow_indication(void *instance, void *sap,
 355                                       LOCAL_FLOW cmd)
 356{
 357        struct ircomm_cb *self = (struct ircomm_cb *) instance;
 358
 359        IRDA_DEBUG(4, "%s()\n", __func__ );
 360
 361        IRDA_ASSERT(self != NULL, return;);
 362        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 363
 364        if (self->notify.flow_indication)
 365                self->notify.flow_indication(self->notify.instance, self, cmd);
 366}
 367
 368
 369