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, see <http://www.gnu.org/licenses/>.
  27 *
  28 ********************************************************************/
  29
  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
  37#include <net/irda/ircomm_event.h>
  38#include <net/irda/ircomm_ttp.h>
  39
  40static int ircomm_ttp_data_indication(void *instance, void *sap,
  41                                      struct sk_buff *skb);
  42static void ircomm_ttp_connect_confirm(void *instance, void *sap,
  43                                       struct qos_info *qos,
  44                                       __u32 max_sdu_size,
  45                                       __u8 max_header_size,
  46                                       struct sk_buff *skb);
  47static void ircomm_ttp_connect_indication(void *instance, void *sap,
  48                                          struct qos_info *qos,
  49                                          __u32 max_sdu_size,
  50                                          __u8 max_header_size,
  51                                          struct sk_buff *skb);
  52static void ircomm_ttp_flow_indication(void *instance, void *sap,
  53                                       LOCAL_FLOW cmd);
  54static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
  55                                             LM_REASON reason,
  56                                             struct sk_buff *skb);
  57static int ircomm_ttp_data_request(struct ircomm_cb *self,
  58                                   struct sk_buff *skb,
  59                                   int clen);
  60static int ircomm_ttp_connect_request(struct ircomm_cb *self,
  61                                      struct sk_buff *userdata,
  62                                      struct ircomm_info *info);
  63static int ircomm_ttp_connect_response(struct ircomm_cb *self,
  64                                       struct sk_buff *userdata);
  65static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
  66                                         struct sk_buff *userdata,
  67                                         struct ircomm_info *info);
  68
  69/*
  70 * Function ircomm_open_tsap (self)
  71 *
  72 *
  73 *
  74 */
  75int ircomm_open_tsap(struct ircomm_cb *self)
  76{
  77        notify_t notify;
  78
  79        /* Register callbacks */
  80        irda_notify_init(&notify);
  81        notify.data_indication       = ircomm_ttp_data_indication;
  82        notify.connect_confirm       = ircomm_ttp_connect_confirm;
  83        notify.connect_indication    = ircomm_ttp_connect_indication;
  84        notify.flow_indication       = ircomm_ttp_flow_indication;
  85        notify.disconnect_indication = ircomm_ttp_disconnect_indication;
  86        notify.instance = self;
  87        strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
  88
  89        self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
  90                                     &notify);
  91        if (!self->tsap) {
  92                pr_debug("%sfailed to allocate tsap\n", __func__);
  93                return -1;
  94        }
  95        self->slsap_sel = self->tsap->stsap_sel;
  96
  97        /*
  98         *  Initialize the call-table for issuing commands
  99         */
 100        self->issue.data_request       = ircomm_ttp_data_request;
 101        self->issue.connect_request    = ircomm_ttp_connect_request;
 102        self->issue.connect_response   = ircomm_ttp_connect_response;
 103        self->issue.disconnect_request = ircomm_ttp_disconnect_request;
 104
 105        return 0;
 106}
 107
 108/*
 109 * Function ircomm_ttp_connect_request (self, userdata)
 110 *
 111 *
 112 *
 113 */
 114static int ircomm_ttp_connect_request(struct ircomm_cb *self,
 115                                      struct sk_buff *userdata,
 116                                      struct ircomm_info *info)
 117{
 118        int ret = 0;
 119
 120        /* Don't forget to refcount it - should be NULL anyway */
 121        if(userdata)
 122                skb_get(userdata);
 123
 124        ret = irttp_connect_request(self->tsap, info->dlsap_sel,
 125                                    info->saddr, info->daddr, NULL,
 126                                    TTP_SAR_DISABLE, userdata);
 127
 128        return ret;
 129}
 130
 131/*
 132 * Function ircomm_ttp_connect_response (self, skb)
 133 *
 134 *
 135 *
 136 */
 137static int ircomm_ttp_connect_response(struct ircomm_cb *self,
 138                                       struct sk_buff *userdata)
 139{
 140        int ret;
 141
 142        /* Don't forget to refcount it - should be NULL anyway */
 143        if(userdata)
 144                skb_get(userdata);
 145
 146        ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata);
 147
 148        return ret;
 149}
 150
 151/*
 152 * Function ircomm_ttp_data_request (self, userdata)
 153 *
 154 *    Send IrCOMM data to IrTTP layer. Currently we do not try to combine
 155 *    control data with pure data, so they will be sent as separate frames.
 156 *    Should not be a big problem though, since control frames are rare. But
 157 *    some of them are sent after connection establishment, so this can
 158 *    increase the latency a bit.
 159 */
 160static int ircomm_ttp_data_request(struct ircomm_cb *self,
 161                                   struct sk_buff *skb,
 162                                   int clen)
 163{
 164        int ret;
 165
 166        IRDA_ASSERT(skb != NULL, return -1;);
 167
 168        pr_debug("%s(), clen=%d\n", __func__ , clen);
 169
 170        /*
 171         * Insert clen field, currently we either send data only, or control
 172         * only frames, to make things easier and avoid queueing
 173         */
 174        IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
 175
 176        /* Don't forget to refcount it - see ircomm_tty_do_softint() */
 177        skb_get(skb);
 178
 179        skb_push(skb, IRCOMM_HEADER_SIZE);
 180
 181        skb->data[0] = clen;
 182
 183        ret = irttp_data_request(self->tsap, skb);
 184        if (ret) {
 185                net_err_ratelimited("%s(), failed\n", __func__);
 186                /* irttp_data_request already free the packet */
 187        }
 188
 189        return ret;
 190}
 191
 192/*
 193 * Function ircomm_ttp_data_indication (instance, sap, skb)
 194 *
 195 *    Incoming data
 196 *
 197 */
 198static int ircomm_ttp_data_indication(void *instance, void *sap,
 199                                      struct sk_buff *skb)
 200{
 201        struct ircomm_cb *self = (struct ircomm_cb *) instance;
 202
 203        IRDA_ASSERT(self != NULL, return -1;);
 204        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 205        IRDA_ASSERT(skb != NULL, return -1;);
 206
 207        ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
 208
 209        /* Drop reference count - see ircomm_tty_data_indication(). */
 210        dev_kfree_skb(skb);
 211
 212        return 0;
 213}
 214
 215static void ircomm_ttp_connect_confirm(void *instance, void *sap,
 216                                       struct qos_info *qos,
 217                                       __u32 max_sdu_size,
 218                                       __u8 max_header_size,
 219                                       struct sk_buff *skb)
 220{
 221        struct ircomm_cb *self = (struct ircomm_cb *) instance;
 222        struct ircomm_info info;
 223
 224        IRDA_ASSERT(self != NULL, return;);
 225        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 226        IRDA_ASSERT(skb != NULL, return;);
 227        IRDA_ASSERT(qos != NULL, goto out;);
 228
 229        if (max_sdu_size != TTP_SAR_DISABLE) {
 230                net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n",
 231                                    __func__);
 232                goto out;
 233        }
 234
 235        info.max_data_size = irttp_get_max_seg_size(self->tsap)
 236                - IRCOMM_HEADER_SIZE;
 237        info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
 238        info.qos = qos;
 239
 240        ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
 241
 242out:
 243        /* Drop reference count - see ircomm_tty_connect_confirm(). */
 244        dev_kfree_skb(skb);
 245}
 246
 247/*
 248 * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size,
 249 *                                         max_header_size, skb)
 250 *
 251 *
 252 *
 253 */
 254static void ircomm_ttp_connect_indication(void *instance, void *sap,
 255                                          struct qos_info *qos,
 256                                          __u32 max_sdu_size,
 257                                          __u8 max_header_size,
 258                                          struct sk_buff *skb)
 259{
 260        struct ircomm_cb *self = (struct ircomm_cb *)instance;
 261        struct ircomm_info info;
 262
 263        IRDA_ASSERT(self != NULL, return;);
 264        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 265        IRDA_ASSERT(skb != NULL, return;);
 266        IRDA_ASSERT(qos != NULL, goto out;);
 267
 268        if (max_sdu_size != TTP_SAR_DISABLE) {
 269                net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n",
 270                                    __func__);
 271                goto out;
 272        }
 273
 274        info.max_data_size = irttp_get_max_seg_size(self->tsap)
 275                - IRCOMM_HEADER_SIZE;
 276        info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
 277        info.qos = qos;
 278
 279        ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
 280
 281out:
 282        /* Drop reference count - see ircomm_tty_connect_indication(). */
 283        dev_kfree_skb(skb);
 284}
 285
 286/*
 287 * Function ircomm_ttp_disconnect_request (self, userdata, info)
 288 *
 289 *
 290 *
 291 */
 292static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
 293                                         struct sk_buff *userdata,
 294                                         struct ircomm_info *info)
 295{
 296        int ret;
 297
 298        /* Don't forget to refcount it - should be NULL anyway */
 299        if(userdata)
 300                skb_get(userdata);
 301
 302        ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
 303
 304        return ret;
 305}
 306
 307/*
 308 * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb)
 309 *
 310 *
 311 *
 312 */
 313static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
 314                                             LM_REASON reason,
 315                                             struct sk_buff *skb)
 316{
 317        struct ircomm_cb *self = (struct ircomm_cb *) instance;
 318        struct ircomm_info info;
 319
 320        IRDA_ASSERT(self != NULL, return;);
 321        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 322
 323        info.reason = reason;
 324
 325        ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
 326
 327        /* Drop reference count - see ircomm_tty_disconnect_indication(). */
 328        if(skb)
 329                dev_kfree_skb(skb);
 330}
 331
 332/*
 333 * Function ircomm_ttp_flow_indication (instance, sap, cmd)
 334 *
 335 *    Layer below is telling us to start or stop the flow of data
 336 *
 337 */
 338static void ircomm_ttp_flow_indication(void *instance, void *sap,
 339                                       LOCAL_FLOW cmd)
 340{
 341        struct ircomm_cb *self = (struct ircomm_cb *) instance;
 342
 343        IRDA_ASSERT(self != NULL, return;);
 344        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 345
 346        if (self->notify.flow_indication)
 347                self->notify.flow_indication(self->notify.instance, self, cmd);
 348}
 349
 350
 351