Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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