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