linux/net/irda/ircomm/ircomm_core.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      ircomm_core.c
   4 * Version:       1.0
   5 * Description:   IrCOMM service interface
   6 * Status:        Experimental.
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Sun Jun  6 20:37:34 1999
   9 * Modified at:   Tue Dec 21 13:26:41 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/module.h>
  33#include <linux/proc_fs.h>
  34#include <linux/seq_file.h>
  35#include <linux/init.h>
  36
  37#include <net/irda/irda.h>
  38#include <net/irda/irmod.h>
  39#include <net/irda/irlmp.h>
  40#include <net/irda/iriap.h>
  41#include <net/irda/irttp.h>
  42#include <net/irda/irias_object.h>
  43
  44#include <net/irda/ircomm_event.h>
  45#include <net/irda/ircomm_lmp.h>
  46#include <net/irda/ircomm_ttp.h>
  47#include <net/irda/ircomm_param.h>
  48#include <net/irda/ircomm_core.h>
  49
  50static int __ircomm_close(struct ircomm_cb *self);
  51static void ircomm_control_indication(struct ircomm_cb *self,
  52                                      struct sk_buff *skb, int clen);
  53
  54#ifdef CONFIG_PROC_FS
  55extern struct proc_dir_entry *proc_irda;
  56static int ircomm_seq_open(struct inode *, struct file *);
  57
  58static const struct file_operations ircomm_proc_fops = {
  59        .owner          = THIS_MODULE,
  60        .open           = ircomm_seq_open,
  61        .read           = seq_read,
  62        .llseek         = seq_lseek,
  63        .release        = seq_release,
  64};
  65#endif /* CONFIG_PROC_FS */
  66
  67hashbin_t *ircomm = NULL;
  68
  69static int __init ircomm_init(void)
  70{
  71        ircomm = hashbin_new(HB_LOCK);
  72        if (ircomm == NULL) {
  73                IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__);
  74                return -ENOMEM;
  75        }
  76
  77#ifdef CONFIG_PROC_FS
  78        { struct proc_dir_entry *ent;
  79        ent = proc_create("ircomm", 0, proc_irda, &ircomm_proc_fops);
  80        if (!ent) {
  81                printk(KERN_ERR "ircomm_init: can't create /proc entry!\n");
  82                return -ENODEV;
  83        }
  84        }
  85#endif /* CONFIG_PROC_FS */
  86
  87        IRDA_MESSAGE("IrCOMM protocol (Dag Brattli)\n");
  88
  89        return 0;
  90}
  91
  92static void __exit ircomm_cleanup(void)
  93{
  94        IRDA_DEBUG(2, "%s()\n", __func__ );
  95
  96        hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
  97
  98#ifdef CONFIG_PROC_FS
  99        remove_proc_entry("ircomm", proc_irda);
 100#endif /* CONFIG_PROC_FS */
 101}
 102
 103/*
 104 * Function ircomm_open (client_notify)
 105 *
 106 *    Start a new IrCOMM instance
 107 *
 108 */
 109struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
 110{
 111        struct ircomm_cb *self = NULL;
 112        int ret;
 113
 114        IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __func__ ,
 115                   service_type);
 116
 117        IRDA_ASSERT(ircomm != NULL, return NULL;);
 118
 119        self = kzalloc(sizeof(struct ircomm_cb), GFP_ATOMIC);
 120        if (self == NULL)
 121                return NULL;
 122
 123        self->notify = *notify;
 124        self->magic = IRCOMM_MAGIC;
 125
 126        /* Check if we should use IrLMP or IrTTP */
 127        if (service_type & IRCOMM_3_WIRE_RAW) {
 128                self->flow_status = FLOW_START;
 129                ret = ircomm_open_lsap(self);
 130        } else
 131                ret = ircomm_open_tsap(self);
 132
 133        if (ret < 0) {
 134                kfree(self);
 135                return NULL;
 136        }
 137
 138        self->service_type = service_type;
 139        self->line = line;
 140
 141        hashbin_insert(ircomm, (irda_queue_t *) self, line, NULL);
 142
 143        ircomm_next_state(self, IRCOMM_IDLE);
 144
 145        return self;
 146}
 147
 148EXPORT_SYMBOL(ircomm_open);
 149
 150/*
 151 * Function ircomm_close_instance (self)
 152 *
 153 *    Remove IrCOMM instance
 154 *
 155 */
 156static int __ircomm_close(struct ircomm_cb *self)
 157{
 158        IRDA_DEBUG(2, "%s()\n", __func__ );
 159
 160        /* Disconnect link if any */
 161        ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
 162
 163        /* Remove TSAP */
 164        if (self->tsap) {
 165                irttp_close_tsap(self->tsap);
 166                self->tsap = NULL;
 167        }
 168
 169        /* Remove LSAP */
 170        if (self->lsap) {
 171                irlmp_close_lsap(self->lsap);
 172                self->lsap = NULL;
 173        }
 174        self->magic = 0;
 175
 176        kfree(self);
 177
 178        return 0;
 179}
 180
 181/*
 182 * Function ircomm_close (self)
 183 *
 184 *    Closes and removes the specified IrCOMM instance
 185 *
 186 */
 187int ircomm_close(struct ircomm_cb *self)
 188{
 189        struct ircomm_cb *entry;
 190
 191        IRDA_ASSERT(self != NULL, return -EIO;);
 192        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
 193
 194        IRDA_DEBUG(0, "%s()\n", __func__ );
 195
 196        entry = hashbin_remove(ircomm, self->line, NULL);
 197
 198        IRDA_ASSERT(entry == self, return -1;);
 199
 200        return __ircomm_close(self);
 201}
 202
 203EXPORT_SYMBOL(ircomm_close);
 204
 205/*
 206 * Function ircomm_connect_request (self, service_type)
 207 *
 208 *    Impl. of this function is differ from one of the reference. This
 209 *    function does discovery as well as sending connect request
 210 *
 211 */
 212int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel,
 213                           __u32 saddr, __u32 daddr, struct sk_buff *skb,
 214                           __u8 service_type)
 215{
 216        struct ircomm_info info;
 217        int ret;
 218
 219        IRDA_DEBUG(2 , "%s()\n", __func__ );
 220
 221        IRDA_ASSERT(self != NULL, return -1;);
 222        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 223
 224        self->service_type= service_type;
 225
 226        info.dlsap_sel = dlsap_sel;
 227        info.saddr = saddr;
 228        info.daddr = daddr;
 229
 230        ret = ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, skb, &info);
 231
 232        return ret;
 233}
 234
 235EXPORT_SYMBOL(ircomm_connect_request);
 236
 237/*
 238 * Function ircomm_connect_indication (self, qos, skb)
 239 *
 240 *    Notify user layer about the incoming connection
 241 *
 242 */
 243void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
 244                               struct ircomm_info *info)
 245{
 246        int clen = 0;
 247
 248        IRDA_DEBUG(2, "%s()\n", __func__ );
 249
 250        /* Check if the packet contains data on the control channel */
 251        if (skb->len > 0)
 252                clen = skb->data[0];
 253
 254        /*
 255         * If there are any data hiding in the control channel, we must
 256         * deliver it first. The side effect is that the control channel
 257         * will be removed from the skb
 258         */
 259        if (self->notify.connect_indication)
 260                self->notify.connect_indication(self->notify.instance, self,
 261                                                info->qos, info->max_data_size,
 262                                                info->max_header_size, skb);
 263        else {
 264                IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 265        }
 266}
 267
 268/*
 269 * Function ircomm_connect_response (self, userdata, max_sdu_size)
 270 *
 271 *    User accepts connection
 272 *
 273 */
 274int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
 275{
 276        int ret;
 277
 278        IRDA_ASSERT(self != NULL, return -1;);
 279        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 280
 281        IRDA_DEBUG(4, "%s()\n", __func__ );
 282
 283        ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
 284
 285        return ret;
 286}
 287
 288EXPORT_SYMBOL(ircomm_connect_response);
 289
 290/*
 291 * Function connect_confirm (self, skb)
 292 *
 293 *    Notify user layer that the link is now connected
 294 *
 295 */
 296void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
 297                            struct ircomm_info *info)
 298{
 299        IRDA_DEBUG(4, "%s()\n", __func__ );
 300
 301        if (self->notify.connect_confirm )
 302                self->notify.connect_confirm(self->notify.instance,
 303                                             self, info->qos,
 304                                             info->max_data_size,
 305                                             info->max_header_size, skb);
 306        else {
 307                IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 308        }
 309}
 310
 311/*
 312 * Function ircomm_data_request (self, userdata)
 313 *
 314 *    Send IrCOMM data to peer device
 315 *
 316 */
 317int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb)
 318{
 319        int ret;
 320
 321        IRDA_DEBUG(4, "%s()\n", __func__ );
 322
 323        IRDA_ASSERT(self != NULL, return -EFAULT;);
 324        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
 325        IRDA_ASSERT(skb != NULL, return -EFAULT;);
 326
 327        ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL);
 328
 329        return ret;
 330}
 331
 332EXPORT_SYMBOL(ircomm_data_request);
 333
 334/*
 335 * Function ircomm_data_indication (self, skb)
 336 *
 337 *    Data arrived, so deliver it to user
 338 *
 339 */
 340void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
 341{
 342        IRDA_DEBUG(4, "%s()\n", __func__ );
 343
 344        IRDA_ASSERT(skb->len > 0, return;);
 345
 346        if (self->notify.data_indication)
 347                self->notify.data_indication(self->notify.instance, self, skb);
 348        else {
 349                IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 350        }
 351}
 352
 353/*
 354 * Function ircomm_process_data (self, skb)
 355 *
 356 *    Data arrived which may contain control channel data
 357 *
 358 */
 359void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
 360{
 361        int clen;
 362
 363        IRDA_ASSERT(skb->len > 0, return;);
 364
 365        clen = skb->data[0];
 366
 367        /*
 368         * Input validation check: a stir4200/mcp2150 combinations sometimes
 369         * results in frames with clen > remaining packet size. These are
 370         * illegal; if we throw away just this frame then it seems to carry on
 371         * fine
 372         */
 373        if (unlikely(skb->len < (clen + 1))) {
 374                IRDA_DEBUG(2, "%s() throwing away illegal frame\n",
 375                           __func__ );
 376                return;
 377        }
 378
 379        /*
 380         * If there are any data hiding in the control channel, we must
 381         * deliver it first. The side effect is that the control channel
 382         * will be removed from the skb
 383         */
 384        if (clen > 0)
 385                ircomm_control_indication(self, skb, clen);
 386
 387        /* Remove control channel from data channel */
 388        skb_pull(skb, clen+1);
 389
 390        if (skb->len)
 391                ircomm_data_indication(self, skb);
 392        else {
 393                IRDA_DEBUG(4, "%s(), data was control info only!\n",
 394                           __func__ );
 395        }
 396}
 397
 398/*
 399 * Function ircomm_control_request (self, params)
 400 *
 401 *    Send control data to peer device
 402 *
 403 */
 404int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb)
 405{
 406        int ret;
 407
 408        IRDA_DEBUG(2, "%s()\n", __func__ );
 409
 410        IRDA_ASSERT(self != NULL, return -EFAULT;);
 411        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
 412        IRDA_ASSERT(skb != NULL, return -EFAULT;);
 413
 414        ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL);
 415
 416        return ret;
 417}
 418
 419EXPORT_SYMBOL(ircomm_control_request);
 420
 421/*
 422 * Function ircomm_control_indication (self, skb)
 423 *
 424 *    Data has arrived on the control channel
 425 *
 426 */
 427static void ircomm_control_indication(struct ircomm_cb *self,
 428                                      struct sk_buff *skb, int clen)
 429{
 430        IRDA_DEBUG(2, "%s()\n", __func__ );
 431
 432        /* Use udata for delivering data on the control channel */
 433        if (self->notify.udata_indication) {
 434                struct sk_buff *ctrl_skb;
 435
 436                /* We don't own the skb, so clone it */
 437                ctrl_skb = skb_clone(skb, GFP_ATOMIC);
 438                if (!ctrl_skb)
 439                        return;
 440
 441                /* Remove data channel from control channel */
 442                skb_trim(ctrl_skb, clen+1);
 443
 444                self->notify.udata_indication(self->notify.instance, self,
 445                                              ctrl_skb);
 446
 447                /* Drop reference count -
 448                 * see ircomm_tty_control_indication(). */
 449                dev_kfree_skb(ctrl_skb);
 450        } else {
 451                IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 452        }
 453}
 454
 455/*
 456 * Function ircomm_disconnect_request (self, userdata, priority)
 457 *
 458 *    User layer wants to disconnect the IrCOMM connection
 459 *
 460 */
 461int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata)
 462{
 463        struct ircomm_info info;
 464        int ret;
 465
 466        IRDA_DEBUG(2, "%s()\n", __func__ );
 467
 468        IRDA_ASSERT(self != NULL, return -1;);
 469        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 470
 471        ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata,
 472                              &info);
 473        return ret;
 474}
 475
 476EXPORT_SYMBOL(ircomm_disconnect_request);
 477
 478/*
 479 * Function disconnect_indication (self, skb)
 480 *
 481 *    Tell user that the link has been disconnected
 482 *
 483 */
 484void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
 485                                  struct ircomm_info *info)
 486{
 487        IRDA_DEBUG(2, "%s()\n", __func__ );
 488
 489        IRDA_ASSERT(info != NULL, return;);
 490
 491        if (self->notify.disconnect_indication) {
 492                self->notify.disconnect_indication(self->notify.instance, self,
 493                                                   info->reason, skb);
 494        } else {
 495                IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 496        }
 497}
 498
 499/*
 500 * Function ircomm_flow_request (self, flow)
 501 *
 502 *
 503 *
 504 */
 505void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
 506{
 507        IRDA_DEBUG(2, "%s()\n", __func__ );
 508
 509        IRDA_ASSERT(self != NULL, return;);
 510        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
 511
 512        if (self->service_type == IRCOMM_3_WIRE_RAW)
 513                return;
 514
 515        irttp_flow_request(self->tsap, flow);
 516}
 517
 518EXPORT_SYMBOL(ircomm_flow_request);
 519
 520#ifdef CONFIG_PROC_FS
 521static void *ircomm_seq_start(struct seq_file *seq, loff_t *pos)
 522{
 523        struct ircomm_cb *self;
 524        loff_t off = 0;
 525
 526        spin_lock_irq(&ircomm->hb_spinlock);
 527
 528        for (self = (struct ircomm_cb *) hashbin_get_first(ircomm);
 529             self != NULL;
 530             self = (struct ircomm_cb *) hashbin_get_next(ircomm)) {
 531                if (off++ == *pos)
 532                        break;
 533
 534        }
 535        return self;
 536}
 537
 538static void *ircomm_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 539{
 540        ++*pos;
 541
 542        return (void *) hashbin_get_next(ircomm);
 543}
 544
 545static void ircomm_seq_stop(struct seq_file *seq, void *v)
 546{
 547        spin_unlock_irq(&ircomm->hb_spinlock);
 548}
 549
 550static int ircomm_seq_show(struct seq_file *seq, void *v)
 551{
 552        const struct ircomm_cb *self = v;
 553
 554        IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EINVAL; );
 555
 556        if(self->line < 0x10)
 557                seq_printf(seq, "ircomm%d", self->line);
 558        else
 559                seq_printf(seq, "irlpt%d", self->line - 0x10);
 560
 561        seq_printf(seq,
 562                   " state: %s, slsap_sel: %#02x, dlsap_sel: %#02x, mode:",
 563                   ircomm_state[ self->state],
 564                   self->slsap_sel, self->dlsap_sel);
 565
 566        if(self->service_type & IRCOMM_3_WIRE_RAW)
 567                seq_printf(seq, " 3-wire-raw");
 568        if(self->service_type & IRCOMM_3_WIRE)
 569                seq_printf(seq, " 3-wire");
 570        if(self->service_type & IRCOMM_9_WIRE)
 571                seq_printf(seq, " 9-wire");
 572        if(self->service_type & IRCOMM_CENTRONICS)
 573                seq_printf(seq, " Centronics");
 574        seq_putc(seq, '\n');
 575
 576        return 0;
 577}
 578
 579static const struct seq_operations ircomm_seq_ops = {
 580        .start  = ircomm_seq_start,
 581        .next   = ircomm_seq_next,
 582        .stop   = ircomm_seq_stop,
 583        .show   = ircomm_seq_show,
 584};
 585
 586static int ircomm_seq_open(struct inode *inode, struct file *file)
 587{
 588        return seq_open(file, &ircomm_seq_ops);
 589}
 590#endif /* CONFIG_PROC_FS */
 591
 592MODULE_AUTHOR("Dag Brattli <dag@brattli.net>");
 593MODULE_DESCRIPTION("IrCOMM protocol");
 594MODULE_LICENSE("GPL");
 595
 596module_init(ircomm_init);
 597module_exit(ircomm_cleanup);
 598
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.