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