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 51 static int __ircomm_close(struct ircomm_cb *self); 52 static void ircomm_control_indication(struct ircomm_cb *self, 53 struct sk_buff *skb, int clen); 54 55 #ifdef CONFIG_PROC_FS 56 extern struct proc_dir_entry *proc_irda; 57 static int ircomm_seq_open(struct inode *, struct file *); 58 59 static 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 68 hashbin_t *ircomm = NULL; 69 70 static 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 93 static 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 */ 110 struct 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_KERNEL); 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 149 EXPORT_SYMBOL(ircomm_open); 150 151 /* 152 * Function ircomm_close_instance (self) 153 * 154 * Remove IrCOMM instance 155 * 156 */ 157 static 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 */ 188 int 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 204 EXPORT_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 */ 213 int 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 236 EXPORT_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 */ 244 void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, 245 struct ircomm_info *info) 246 { 247 IRDA_DEBUG(2, "%s()\n", __func__ ); 248 249 /* 250 * If there are any data hiding in the control channel, we must 251 * deliver it first. The side effect is that the control channel 252 * will be removed from the skb 253 */ 254 if (self->notify.connect_indication) 255 self->notify.connect_indication(self->notify.instance, self, 256 info->qos, info->max_data_size, 257 info->max_header_size, skb); 258 else { 259 IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); 260 } 261 } 262 263 /* 264 * Function ircomm_connect_response (self, userdata, max_sdu_size) 265 * 266 * User accepts connection 267 * 268 */ 269 int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata) 270 { 271 int ret; 272 273 IRDA_ASSERT(self != NULL, return -1;); 274 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); 275 276 IRDA_DEBUG(4, "%s()\n", __func__ ); 277 278 ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL); 279 280 return ret; 281 } 282 283 EXPORT_SYMBOL(ircomm_connect_response); 284 285 /* 286 * Function connect_confirm (self, skb) 287 * 288 * Notify user layer that the link is now connected 289 * 290 */ 291 void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, 292 struct ircomm_info *info) 293 { 294 IRDA_DEBUG(4, "%s()\n", __func__ ); 295 296 if (self->notify.connect_confirm ) 297 self->notify.connect_confirm(self->notify.instance, 298 self, info->qos, 299 info->max_data_size, 300 info->max_header_size, skb); 301 else { 302 IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); 303 } 304 } 305 306 /* 307 * Function ircomm_data_request (self, userdata) 308 * 309 * Send IrCOMM data to peer device 310 * 311 */ 312 int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb) 313 { 314 int ret; 315 316 IRDA_DEBUG(4, "%s()\n", __func__ ); 317 318 IRDA_ASSERT(self != NULL, return -EFAULT;); 319 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;); 320 IRDA_ASSERT(skb != NULL, return -EFAULT;); 321 322 ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL); 323 324 return ret; 325 } 326 327 EXPORT_SYMBOL(ircomm_data_request); 328 329 /* 330 * Function ircomm_data_indication (self, skb) 331 * 332 * Data arrived, so deliver it to user 333 * 334 */ 335 void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb) 336 { 337 IRDA_DEBUG(4, "%s()\n", __func__ ); 338 339 IRDA_ASSERT(skb->len > 0, return;); 340 341 if (self->notify.data_indication) 342 self->notify.data_indication(self->notify.instance, self, skb); 343 else { 344 IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); 345 } 346 } 347 348 /* 349 * Function ircomm_process_data (self, skb) 350 * 351 * Data arrived which may contain control channel data 352 * 353 */ 354 void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb) 355 { 356 int clen; 357 358 IRDA_ASSERT(skb->len > 0, return;); 359 360 clen = skb->data[0]; 361 362 /* 363 * Input validation check: a stir4200/mcp2150 combinations sometimes 364 * results in frames with clen > remaining packet size. These are 365 * illegal; if we throw away just this frame then it seems to carry on 366 * fine 367 */ 368 if (unlikely(skb->len < (clen + 1))) { 369 IRDA_DEBUG(2, "%s() throwing away illegal frame\n", 370 __func__ ); 371 return; 372 } 373 374 /* 375 * If there are any data hiding in the control channel, we must 376 * deliver it first. The side effect is that the control channel 377 * will be removed from the skb 378 */ 379 if (clen > 0) 380 ircomm_control_indication(self, skb, clen); 381 382 /* Remove control channel from data channel */ 383 skb_pull(skb, clen+1); 384 385 if (skb->len) 386 ircomm_data_indication(self, skb); 387 else { 388 IRDA_DEBUG(4, "%s(), data was control info only!\n", 389 __func__ ); 390 } 391 } 392 393 /* 394 * Function ircomm_control_request (self, params) 395 * 396 * Send control data to peer device 397 * 398 */ 399 int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb) 400 { 401 int ret; 402 403 IRDA_DEBUG(2, "%s()\n", __func__ ); 404 405 IRDA_ASSERT(self != NULL, return -EFAULT;); 406 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;); 407 IRDA_ASSERT(skb != NULL, return -EFAULT;); 408 409 ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL); 410 411 return ret; 412 } 413 414 EXPORT_SYMBOL(ircomm_control_request); 415 416 /* 417 * Function ircomm_control_indication (self, skb) 418 * 419 * Data has arrived on the control channel 420 * 421 */ 422 static void ircomm_control_indication(struct ircomm_cb *self, 423 struct sk_buff *skb, int clen) 424 { 425 IRDA_DEBUG(2, "%s()\n", __func__ ); 426 427 /* Use udata for delivering data on the control channel */ 428 if (self->notify.udata_indication) { 429 struct sk_buff *ctrl_skb; 430 431 /* We don't own the skb, so clone it */ 432 ctrl_skb = skb_clone(skb, GFP_ATOMIC); 433 if (!ctrl_skb) 434 return; 435 436 /* Remove data channel from control channel */ 437 skb_trim(ctrl_skb, clen+1); 438 439 self->notify.udata_indication(self->notify.instance, self, 440 ctrl_skb); 441 442 /* Drop reference count - 443 * see ircomm_tty_control_indication(). */ 444 dev_kfree_skb(ctrl_skb); 445 } else { 446 IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); 447 } 448 } 449 450 /* 451 * Function ircomm_disconnect_request (self, userdata, priority) 452 * 453 * User layer wants to disconnect the IrCOMM connection 454 * 455 */ 456 int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata) 457 { 458 struct ircomm_info info; 459 int ret; 460 461 IRDA_DEBUG(2, "%s()\n", __func__ ); 462 463 IRDA_ASSERT(self != NULL, return -1;); 464 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); 465 466 ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata, 467 &info); 468 return ret; 469 } 470 471 EXPORT_SYMBOL(ircomm_disconnect_request); 472 473 /* 474 * Function disconnect_indication (self, skb) 475 * 476 * Tell user that the link has been disconnected 477 * 478 */ 479 void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, 480 struct ircomm_info *info) 481 { 482 IRDA_DEBUG(2, "%s()\n", __func__ ); 483 484 IRDA_ASSERT(info != NULL, return;); 485 486 if (self->notify.disconnect_indication) { 487 self->notify.disconnect_indication(self->notify.instance, self, 488 info->reason, skb); 489 } else { 490 IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); 491 } 492 } 493 494 /* 495 * Function ircomm_flow_request (self, flow) 496 * 497 * 498 * 499 */ 500 void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow) 501 { 502 IRDA_DEBUG(2, "%s()\n", __func__ ); 503 504 IRDA_ASSERT(self != NULL, return;); 505 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 506 507 if (self->service_type == IRCOMM_3_WIRE_RAW) 508 return; 509 510 irttp_flow_request(self->tsap, flow); 511 } 512 513 EXPORT_SYMBOL(ircomm_flow_request); 514 515 #ifdef CONFIG_PROC_FS 516 static void *ircomm_seq_start(struct seq_file *seq, loff_t *pos) 517 { 518 struct ircomm_cb *self; 519 loff_t off = 0; 520 521 spin_lock_irq(&ircomm->hb_spinlock); 522 523 for (self = (struct ircomm_cb *) hashbin_get_first(ircomm); 524 self != NULL; 525 self = (struct ircomm_cb *) hashbin_get_next(ircomm)) { 526 if (off++ == *pos) 527 break; 528 529 } 530 return self; 531 } 532 533 static void *ircomm_seq_next(struct seq_file *seq, void *v, loff_t *pos) 534 { 535 ++*pos; 536 537 return (void *) hashbin_get_next(ircomm); 538 } 539 540 static void ircomm_seq_stop(struct seq_file *seq, void *v) 541 { 542 spin_unlock_irq(&ircomm->hb_spinlock); 543 } 544 545 static int ircomm_seq_show(struct seq_file *seq, void *v) 546 { 547 const struct ircomm_cb *self = v; 548 549 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EINVAL; ); 550 551 if(self->line < 0x10) 552 seq_printf(seq, "ircomm%d", self->line); 553 else 554 seq_printf(seq, "irlpt%d", self->line - 0x10); 555 556 seq_printf(seq, 557 " state: %s, slsap_sel: %#02x, dlsap_sel: %#02x, mode:", 558 ircomm_state[ self->state], 559 self->slsap_sel, self->dlsap_sel); 560 561 if(self->service_type & IRCOMM_3_WIRE_RAW) 562 seq_printf(seq, " 3-wire-raw"); 563 if(self->service_type & IRCOMM_3_WIRE) 564 seq_printf(seq, " 3-wire"); 565 if(self->service_type & IRCOMM_9_WIRE) 566 seq_printf(seq, " 9-wire"); 567 if(self->service_type & IRCOMM_CENTRONICS) 568 seq_printf(seq, " Centronics"); 569 seq_putc(seq, '\n'); 570 571 return 0; 572 } 573 574 static const struct seq_operations ircomm_seq_ops = { 575 .start = ircomm_seq_start, 576 .next = ircomm_seq_next, 577 .stop = ircomm_seq_stop, 578 .show = ircomm_seq_show, 579 }; 580 581 static int ircomm_seq_open(struct inode *inode, struct file *file) 582 { 583 return seq_open(file, &ircomm_seq_ops); 584 } 585 #endif /* CONFIG_PROC_FS */ 586 587 MODULE_AUTHOR("Dag Brattli <dag@brattli.net>"); 588 MODULE_DESCRIPTION("IrCOMM protocol"); 589 MODULE_LICENSE("GPL"); 590 591 module_init(ircomm_init); 592 module_exit(ircomm_cleanup); 593
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.