1 /********************************************************************* 2 * 3 * Filename: iriap.c 4 * Version: 0.8 5 * Description: Information Access Protocol (IAP) 6 * Status: Experimental. 7 * Author: Dag Brattli <dagb@cs.uit.no> 8 * Created at: Thu Aug 21 00:02:07 1997 9 * Modified at: Sat Dec 25 16:42:42 1999 10 * Modified by: Dag Brattli <dagb@cs.uit.no> 11 * 12 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 13 * All Rights Reserved. 14 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> 15 * 16 * This program is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU General Public License as 18 * published by the Free Software Foundation; either version 2 of 19 * the License, or (at your option) any later version. 20 * 21 * Neither Dag Brattli nor University of Tromsø admit liability nor 22 * provide warranty for any of this software. This material is 23 * provided "AS-IS" and at no charge. 24 * 25 ********************************************************************/ 26 27 #include <linux/module.h> 28 #include <linux/types.h> 29 #include <linux/skbuff.h> 30 #include <linux/fs.h> 31 #include <linux/string.h> 32 #include <linux/init.h> 33 #include <linux/seq_file.h> 34 #include <linux/slab.h> 35 36 #include <asm/byteorder.h> 37 #include <asm/unaligned.h> 38 39 #include <net/irda/irda.h> 40 #include <net/irda/irttp.h> 41 #include <net/irda/irlmp.h> 42 #include <net/irda/irias_object.h> 43 #include <net/irda/iriap_event.h> 44 #include <net/irda/iriap.h> 45 46 /* FIXME: This one should go in irlmp.c */ 47 static const char *const ias_charset_types[] __maybe_unused = { 48 "CS_ASCII", 49 "CS_ISO_8859_1", 50 "CS_ISO_8859_2", 51 "CS_ISO_8859_3", 52 "CS_ISO_8859_4", 53 "CS_ISO_8859_5", 54 "CS_ISO_8859_6", 55 "CS_ISO_8859_7", 56 "CS_ISO_8859_8", 57 "CS_ISO_8859_9", 58 "CS_UNICODE" 59 }; 60 61 static hashbin_t *iriap = NULL; 62 static void *service_handle; 63 64 static void __iriap_close(struct iriap_cb *self); 65 static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode); 66 static void iriap_disconnect_indication(void *instance, void *sap, 67 LM_REASON reason, struct sk_buff *skb); 68 static void iriap_connect_indication(void *instance, void *sap, 69 struct qos_info *qos, __u32 max_sdu_size, 70 __u8 max_header_size, 71 struct sk_buff *skb); 72 static void iriap_connect_confirm(void *instance, void *sap, 73 struct qos_info *qos, 74 __u32 max_sdu_size, __u8 max_header_size, 75 struct sk_buff *skb); 76 static int iriap_data_indication(void *instance, void *sap, 77 struct sk_buff *skb); 78 79 static void iriap_watchdog_timer_expired(void *data); 80 81 static inline void iriap_start_watchdog_timer(struct iriap_cb *self, 82 int timeout) 83 { 84 irda_start_timer(&self->watchdog_timer, timeout, self, 85 iriap_watchdog_timer_expired); 86 } 87 88 static struct lock_class_key irias_objects_key; 89 90 /* 91 * Function iriap_init (void) 92 * 93 * Initializes the IrIAP layer, called by the module initialization code 94 * in irmod.c 95 */ 96 int __init iriap_init(void) 97 { 98 struct ias_object *obj; 99 struct iriap_cb *server; 100 __u8 oct_seq[6]; 101 __u16 hints; 102 103 /* Allocate master array */ 104 iriap = hashbin_new(HB_LOCK); 105 if (!iriap) 106 return -ENOMEM; 107 108 /* Object repository - defined in irias_object.c */ 109 irias_objects = hashbin_new(HB_LOCK); 110 if (!irias_objects) { 111 net_warn_ratelimited("%s: Can't allocate irias_objects hashbin!\n", 112 __func__); 113 hashbin_delete(iriap, NULL); 114 return -ENOMEM; 115 } 116 117 lockdep_set_class_and_name(&irias_objects->hb_spinlock, &irias_objects_key, 118 "irias_objects"); 119 120 /* 121 * Register some default services for IrLMP 122 */ 123 hints = irlmp_service_to_hint(S_COMPUTER); 124 service_handle = irlmp_register_service(hints); 125 126 /* Register the Device object with LM-IAS */ 127 obj = irias_new_object("Device", IAS_DEVICE_ID); 128 irias_add_string_attrib(obj, "DeviceName", "Linux", IAS_KERNEL_ATTR); 129 130 oct_seq[0] = 0x01; /* Version 1 */ 131 oct_seq[1] = 0x00; /* IAS support bits */ 132 oct_seq[2] = 0x00; /* LM-MUX support bits */ 133 #ifdef CONFIG_IRDA_ULTRA 134 oct_seq[2] |= 0x04; /* Connectionless Data support */ 135 #endif 136 irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3, 137 IAS_KERNEL_ATTR); 138 irias_insert_object(obj); 139 140 /* 141 * Register server support with IrLMP so we can accept incoming 142 * connections 143 */ 144 server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); 145 if (!server) { 146 pr_debug("%s(), unable to open server\n", __func__); 147 return -1; 148 } 149 iriap_register_lsap(server, LSAP_IAS, IAS_SERVER); 150 151 return 0; 152 } 153 154 /* 155 * Function iriap_cleanup (void) 156 * 157 * Initializes the IrIAP layer, called by the module cleanup code in 158 * irmod.c 159 */ 160 void iriap_cleanup(void) 161 { 162 irlmp_unregister_service(service_handle); 163 164 hashbin_delete(iriap, (FREE_FUNC) __iriap_close); 165 hashbin_delete(irias_objects, (FREE_FUNC) __irias_delete_object); 166 } 167 168 /* 169 * Function iriap_open (void) 170 * 171 * Opens an instance of the IrIAP layer, and registers with IrLMP 172 */ 173 struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, 174 CONFIRM_CALLBACK callback) 175 { 176 struct iriap_cb *self; 177 178 self = kzalloc(sizeof(*self), GFP_ATOMIC); 179 if (!self) 180 return NULL; 181 182 /* 183 * Initialize instance 184 */ 185 186 self->magic = IAS_MAGIC; 187 self->mode = mode; 188 if (mode == IAS_CLIENT) { 189 if (iriap_register_lsap(self, slsap_sel, mode)) { 190 kfree(self); 191 return NULL; 192 } 193 } 194 195 self->confirm = callback; 196 self->priv = priv; 197 198 /* iriap_getvaluebyclass_request() will construct packets before 199 * we connect, so this must have a sane value... Jean II */ 200 self->max_header_size = LMP_MAX_HEADER; 201 202 init_timer(&self->watchdog_timer); 203 204 hashbin_insert(iriap, (irda_queue_t *) self, (long) self, NULL); 205 206 /* Initialize state machines */ 207 iriap_next_client_state(self, S_DISCONNECT); 208 iriap_next_call_state(self, S_MAKE_CALL); 209 iriap_next_server_state(self, R_DISCONNECT); 210 iriap_next_r_connect_state(self, R_WAITING); 211 212 return self; 213 } 214 EXPORT_SYMBOL(iriap_open); 215 216 /* 217 * Function __iriap_close (self) 218 * 219 * Removes (deallocates) the IrIAP instance 220 * 221 */ 222 static void __iriap_close(struct iriap_cb *self) 223 { 224 IRDA_ASSERT(self != NULL, return;); 225 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 226 227 del_timer(&self->watchdog_timer); 228 229 if (self->request_skb) 230 dev_kfree_skb(self->request_skb); 231 232 self->magic = 0; 233 234 kfree(self); 235 } 236 237 /* 238 * Function iriap_close (void) 239 * 240 * Closes IrIAP and deregisters with IrLMP 241 */ 242 void iriap_close(struct iriap_cb *self) 243 { 244 struct iriap_cb *entry; 245 246 IRDA_ASSERT(self != NULL, return;); 247 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 248 249 if (self->lsap) { 250 irlmp_close_lsap(self->lsap); 251 self->lsap = NULL; 252 } 253 254 entry = (struct iriap_cb *) hashbin_remove(iriap, (long) self, NULL); 255 IRDA_ASSERT(entry == self, return;); 256 257 __iriap_close(self); 258 } 259 EXPORT_SYMBOL(iriap_close); 260 261 static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode) 262 { 263 notify_t notify; 264 265 irda_notify_init(¬ify); 266 notify.connect_confirm = iriap_connect_confirm; 267 notify.connect_indication = iriap_connect_indication; 268 notify.disconnect_indication = iriap_disconnect_indication; 269 notify.data_indication = iriap_data_indication; 270 notify.instance = self; 271 if (mode == IAS_CLIENT) 272 strcpy(notify.name, "IrIAS cli"); 273 else 274 strcpy(notify.name, "IrIAS srv"); 275 276 self->lsap = irlmp_open_lsap(slsap_sel, ¬ify, 0); 277 if (self->lsap == NULL) { 278 net_err_ratelimited("%s: Unable to allocated LSAP!\n", 279 __func__); 280 return -1; 281 } 282 self->slsap_sel = self->lsap->slsap_sel; 283 284 return 0; 285 } 286 287 /* 288 * Function iriap_disconnect_indication (handle, reason) 289 * 290 * Got disconnect, so clean up everything associated with this connection 291 * 292 */ 293 static void iriap_disconnect_indication(void *instance, void *sap, 294 LM_REASON reason, 295 struct sk_buff *skb) 296 { 297 struct iriap_cb *self; 298 299 pr_debug("%s(), reason=%s [%d]\n", __func__, 300 irlmp_reason_str(reason), reason); 301 302 self = instance; 303 304 IRDA_ASSERT(self != NULL, return;); 305 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 306 307 IRDA_ASSERT(iriap != NULL, return;); 308 309 del_timer(&self->watchdog_timer); 310 311 /* Not needed */ 312 if (skb) 313 dev_kfree_skb(skb); 314 315 if (self->mode == IAS_CLIENT) { 316 pr_debug("%s(), disconnect as client\n", __func__); 317 318 319 iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION, 320 NULL); 321 /* 322 * Inform service user that the request failed by sending 323 * it a NULL value. Warning, the client might close us, so 324 * remember no to use self anymore after calling confirm 325 */ 326 if (self->confirm) 327 self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); 328 } else { 329 pr_debug("%s(), disconnect as server\n", __func__); 330 iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, 331 NULL); 332 iriap_close(self); 333 } 334 } 335 336 /* 337 * Function iriap_disconnect_request (handle) 338 */ 339 static void iriap_disconnect_request(struct iriap_cb *self) 340 { 341 struct sk_buff *tx_skb; 342 343 IRDA_ASSERT(self != NULL, return;); 344 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 345 346 tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); 347 if (tx_skb == NULL) { 348 pr_debug("%s(), Could not allocate an sk_buff of length %d\n", 349 __func__, LMP_MAX_HEADER); 350 return; 351 } 352 353 /* 354 * Reserve space for MUX control and LAP header 355 */ 356 skb_reserve(tx_skb, LMP_MAX_HEADER); 357 358 irlmp_disconnect_request(self->lsap, tx_skb); 359 } 360 361 /* 362 * Function iriap_getvaluebyclass (addr, name, attr) 363 * 364 * Retrieve all values from attribute in all objects with given class 365 * name 366 */ 367 int iriap_getvaluebyclass_request(struct iriap_cb *self, 368 __u32 saddr, __u32 daddr, 369 char *name, char *attr) 370 { 371 struct sk_buff *tx_skb; 372 int name_len, attr_len, skb_len; 373 __u8 *frame; 374 375 IRDA_ASSERT(self != NULL, return -1;); 376 IRDA_ASSERT(self->magic == IAS_MAGIC, return -1;); 377 378 /* Client must supply the destination device address */ 379 if (!daddr) 380 return -1; 381 382 self->daddr = daddr; 383 self->saddr = saddr; 384 385 /* 386 * Save operation, so we know what the later indication is about 387 */ 388 self->operation = GET_VALUE_BY_CLASS; 389 390 /* Give ourselves 10 secs to finish this operation */ 391 iriap_start_watchdog_timer(self, 10*HZ); 392 393 name_len = strlen(name); /* Up to IAS_MAX_CLASSNAME = 60 */ 394 attr_len = strlen(attr); /* Up to IAS_MAX_ATTRIBNAME = 60 */ 395 396 skb_len = self->max_header_size+2+name_len+1+attr_len+4; 397 tx_skb = alloc_skb(skb_len, GFP_ATOMIC); 398 if (!tx_skb) 399 return -ENOMEM; 400 401 /* Reserve space for MUX and LAP header */ 402 skb_reserve(tx_skb, self->max_header_size); 403 skb_put(tx_skb, 3+name_len+attr_len); 404 frame = tx_skb->data; 405 406 /* Build frame */ 407 frame[0] = IAP_LST | GET_VALUE_BY_CLASS; 408 frame[1] = name_len; /* Insert length of name */ 409 memcpy(frame+2, name, name_len); /* Insert name */ 410 frame[2+name_len] = attr_len; /* Insert length of attr */ 411 memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */ 412 413 iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, tx_skb); 414 415 /* Drop reference count - see state_s_disconnect(). */ 416 dev_kfree_skb(tx_skb); 417 418 return 0; 419 } 420 EXPORT_SYMBOL(iriap_getvaluebyclass_request); 421 422 /* 423 * Function iriap_getvaluebyclass_confirm (self, skb) 424 * 425 * Got result from GetValueByClass command. Parse it and return result 426 * to service user. 427 * 428 */ 429 static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, 430 struct sk_buff *skb) 431 { 432 struct ias_value *value; 433 int charset; 434 __u32 value_len; 435 __u32 tmp_cpu32; 436 __u16 obj_id; 437 __u16 len; 438 __u8 type; 439 __u8 *fp; 440 int n; 441 442 IRDA_ASSERT(self != NULL, return;); 443 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 444 IRDA_ASSERT(skb != NULL, return;); 445 446 /* Initialize variables */ 447 fp = skb->data; 448 n = 2; 449 450 /* Get length, MSB first */ 451 len = get_unaligned_be16(fp + n); 452 n += 2; 453 454 pr_debug("%s(), len=%d\n", __func__, len); 455 456 /* Get object ID, MSB first */ 457 obj_id = get_unaligned_be16(fp + n); 458 n += 2; 459 460 type = fp[n++]; 461 pr_debug("%s(), Value type = %d\n", __func__, type); 462 463 switch (type) { 464 case IAS_INTEGER: 465 memcpy(&tmp_cpu32, fp+n, 4); n += 4; 466 be32_to_cpus(&tmp_cpu32); 467 value = irias_new_integer_value(tmp_cpu32); 468 469 /* Legal values restricted to 0x01-0x6f, page 15 irttp */ 470 pr_debug("%s(), lsap=%d\n", __func__, value->t.integer); 471 break; 472 case IAS_STRING: 473 charset = fp[n++]; 474 475 switch (charset) { 476 case CS_ASCII: 477 break; 478 /* case CS_ISO_8859_1: */ 479 /* case CS_ISO_8859_2: */ 480 /* case CS_ISO_8859_3: */ 481 /* case CS_ISO_8859_4: */ 482 /* case CS_ISO_8859_5: */ 483 /* case CS_ISO_8859_6: */ 484 /* case CS_ISO_8859_7: */ 485 /* case CS_ISO_8859_8: */ 486 /* case CS_ISO_8859_9: */ 487 /* case CS_UNICODE: */ 488 default: 489 pr_debug("%s(), charset [%d] %s, not supported\n", 490 __func__, charset, 491 charset < ARRAY_SIZE(ias_charset_types) ? 492 ias_charset_types[charset] : 493 "(unknown)"); 494 495 /* Aborting, close connection! */ 496 iriap_disconnect_request(self); 497 return; 498 /* break; */ 499 } 500 value_len = fp[n++]; 501 pr_debug("%s(), strlen=%d\n", __func__, value_len); 502 503 /* Make sure the string is null-terminated */ 504 if (n + value_len < skb->len) 505 fp[n + value_len] = 0x00; 506 pr_debug("Got string %s\n", fp+n); 507 508 /* Will truncate to IAS_MAX_STRING bytes */ 509 value = irias_new_string_value(fp+n); 510 break; 511 case IAS_OCT_SEQ: 512 value_len = get_unaligned_be16(fp + n); 513 n += 2; 514 515 /* Will truncate to IAS_MAX_OCTET_STRING bytes */ 516 value = irias_new_octseq_value(fp+n, value_len); 517 break; 518 default: 519 value = irias_new_missing_value(); 520 break; 521 } 522 523 /* Finished, close connection! */ 524 iriap_disconnect_request(self); 525 526 /* Warning, the client might close us, so remember no to use self 527 * anymore after calling confirm 528 */ 529 if (self->confirm) 530 self->confirm(IAS_SUCCESS, obj_id, value, self->priv); 531 else { 532 pr_debug("%s(), missing handler!\n", __func__); 533 irias_delete_value(value); 534 } 535 } 536 537 /* 538 * Function iriap_getvaluebyclass_response () 539 * 540 * Send answer back to remote LM-IAS 541 * 542 */ 543 static void iriap_getvaluebyclass_response(struct iriap_cb *self, 544 __u16 obj_id, 545 __u8 ret_code, 546 struct ias_value *value) 547 { 548 struct sk_buff *tx_skb; 549 int n; 550 __be32 tmp_be32; 551 __be16 tmp_be16; 552 __u8 *fp; 553 554 IRDA_ASSERT(self != NULL, return;); 555 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 556 IRDA_ASSERT(value != NULL, return;); 557 IRDA_ASSERT(value->len <= 1024, return;); 558 559 /* Initialize variables */ 560 n = 0; 561 562 /* 563 * We must adjust the size of the response after the length of the 564 * value. We add 32 bytes because of the 6 bytes for the frame and 565 * max 5 bytes for the value coding. 566 */ 567 tx_skb = alloc_skb(value->len + self->max_header_size + 32, 568 GFP_ATOMIC); 569 if (!tx_skb) 570 return; 571 572 /* Reserve space for MUX and LAP header */ 573 skb_reserve(tx_skb, self->max_header_size); 574 skb_put(tx_skb, 6); 575 576 fp = tx_skb->data; 577 578 /* Build frame */ 579 fp[n++] = GET_VALUE_BY_CLASS | IAP_LST; 580 fp[n++] = ret_code; 581 582 /* Insert list length (MSB first) */ 583 tmp_be16 = htons(0x0001); 584 memcpy(fp+n, &tmp_be16, 2); n += 2; 585 586 /* Insert object identifier ( MSB first) */ 587 tmp_be16 = cpu_to_be16(obj_id); 588 memcpy(fp+n, &tmp_be16, 2); n += 2; 589 590 switch (value->type) { 591 case IAS_STRING: 592 skb_put(tx_skb, 3 + value->len); 593 fp[n++] = value->type; 594 fp[n++] = 0; /* ASCII */ 595 fp[n++] = (__u8) value->len; 596 memcpy(fp+n, value->t.string, value->len); n+=value->len; 597 break; 598 case IAS_INTEGER: 599 skb_put(tx_skb, 5); 600 fp[n++] = value->type; 601 602 tmp_be32 = cpu_to_be32(value->t.integer); 603 memcpy(fp+n, &tmp_be32, 4); n += 4; 604 break; 605 case IAS_OCT_SEQ: 606 skb_put(tx_skb, 3 + value->len); 607 fp[n++] = value->type; 608 609 tmp_be16 = cpu_to_be16(value->len); 610 memcpy(fp+n, &tmp_be16, 2); n += 2; 611 memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len; 612 break; 613 case IAS_MISSING: 614 pr_debug("%s: sending IAS_MISSING\n", __func__); 615 skb_put(tx_skb, 1); 616 fp[n++] = value->type; 617 break; 618 default: 619 pr_debug("%s(), type not implemented!\n", __func__); 620 break; 621 } 622 iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb); 623 624 /* Drop reference count - see state_r_execute(). */ 625 dev_kfree_skb(tx_skb); 626 } 627 628 /* 629 * Function iriap_getvaluebyclass_indication (self, skb) 630 * 631 * getvaluebyclass is requested from peer LM-IAS 632 * 633 */ 634 static void iriap_getvaluebyclass_indication(struct iriap_cb *self, 635 struct sk_buff *skb) 636 { 637 struct ias_object *obj; 638 struct ias_attrib *attrib; 639 int name_len; 640 int attr_len; 641 char name[IAS_MAX_CLASSNAME + 1]; /* 60 bytes */ 642 char attr[IAS_MAX_ATTRIBNAME + 1]; /* 60 bytes */ 643 __u8 *fp; 644 int n; 645 646 IRDA_ASSERT(self != NULL, return;); 647 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 648 IRDA_ASSERT(skb != NULL, return;); 649 650 fp = skb->data; 651 n = 1; 652 653 name_len = fp[n++]; 654 655 IRDA_ASSERT(name_len < IAS_MAX_CLASSNAME + 1, return;); 656 657 memcpy(name, fp+n, name_len); n+=name_len; 658 name[name_len] = '\0'; 659 660 attr_len = fp[n++]; 661 662 IRDA_ASSERT(attr_len < IAS_MAX_ATTRIBNAME + 1, return;); 663 664 memcpy(attr, fp+n, attr_len); n+=attr_len; 665 attr[attr_len] = '\0'; 666 667 pr_debug("LM-IAS: Looking up %s: %s\n", name, attr); 668 obj = irias_find_object(name); 669 670 if (obj == NULL) { 671 pr_debug("LM-IAS: Object %s not found\n", name); 672 iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN, 673 &irias_missing); 674 return; 675 } 676 pr_debug("LM-IAS: found %s, id=%d\n", obj->name, obj->id); 677 678 attrib = irias_find_attrib(obj, attr); 679 if (attrib == NULL) { 680 pr_debug("LM-IAS: Attribute %s not found\n", attr); 681 iriap_getvaluebyclass_response(self, obj->id, 682 IAS_ATTRIB_UNKNOWN, 683 &irias_missing); 684 return; 685 } 686 687 /* We have a match; send the value. */ 688 iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS, 689 attrib->value); 690 } 691 692 /* 693 * Function iriap_send_ack (void) 694 * 695 * Currently not used 696 * 697 */ 698 void iriap_send_ack(struct iriap_cb *self) 699 { 700 struct sk_buff *tx_skb; 701 __u8 *frame; 702 703 IRDA_ASSERT(self != NULL, return;); 704 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 705 706 tx_skb = alloc_skb(LMP_MAX_HEADER + 1, GFP_ATOMIC); 707 if (!tx_skb) 708 return; 709 710 /* Reserve space for MUX and LAP header */ 711 skb_reserve(tx_skb, self->max_header_size); 712 skb_put(tx_skb, 1); 713 frame = tx_skb->data; 714 715 /* Build frame */ 716 frame[0] = IAP_LST | IAP_ACK | self->operation; 717 718 irlmp_data_request(self->lsap, tx_skb); 719 } 720 721 void iriap_connect_request(struct iriap_cb *self) 722 { 723 int ret; 724 725 IRDA_ASSERT(self != NULL, return;); 726 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 727 728 ret = irlmp_connect_request(self->lsap, LSAP_IAS, 729 self->saddr, self->daddr, 730 NULL, NULL); 731 if (ret < 0) { 732 pr_debug("%s(), connect failed!\n", __func__); 733 self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); 734 } 735 } 736 737 /* 738 * Function iriap_connect_confirm (handle, skb) 739 * 740 * LSAP connection confirmed! 741 * 742 */ 743 static void iriap_connect_confirm(void *instance, void *sap, 744 struct qos_info *qos, __u32 max_seg_size, 745 __u8 max_header_size, 746 struct sk_buff *skb) 747 { 748 struct iriap_cb *self; 749 750 self = instance; 751 752 IRDA_ASSERT(self != NULL, return;); 753 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 754 IRDA_ASSERT(skb != NULL, return;); 755 756 self->max_data_size = max_seg_size; 757 self->max_header_size = max_header_size; 758 759 del_timer(&self->watchdog_timer); 760 761 iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb); 762 763 /* Drop reference count - see state_s_make_call(). */ 764 dev_kfree_skb(skb); 765 } 766 767 /* 768 * Function iriap_connect_indication ( handle, skb) 769 * 770 * Remote LM-IAS is requesting connection 771 * 772 */ 773 static void iriap_connect_indication(void *instance, void *sap, 774 struct qos_info *qos, __u32 max_seg_size, 775 __u8 max_header_size, 776 struct sk_buff *skb) 777 { 778 struct iriap_cb *self, *new; 779 780 self = instance; 781 782 IRDA_ASSERT(skb != NULL, return;); 783 IRDA_ASSERT(self != NULL, goto out;); 784 IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;); 785 786 /* Start new server */ 787 new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); 788 if (!new) { 789 pr_debug("%s(), open failed\n", __func__); 790 goto out; 791 } 792 793 /* Now attach up the new "socket" */ 794 new->lsap = irlmp_dup(self->lsap, new); 795 if (!new->lsap) { 796 pr_debug("%s(), dup failed!\n", __func__); 797 goto out; 798 } 799 800 new->max_data_size = max_seg_size; 801 new->max_header_size = max_header_size; 802 803 /* Clean up the original one to keep it in listen state */ 804 irlmp_listen(self->lsap); 805 806 iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb); 807 808 out: 809 /* Drop reference count - see state_r_disconnect(). */ 810 dev_kfree_skb(skb); 811 } 812 813 /* 814 * Function iriap_data_indication (handle, skb) 815 * 816 * Receives data from connection identified by handle from IrLMP 817 * 818 */ 819 static int iriap_data_indication(void *instance, void *sap, 820 struct sk_buff *skb) 821 { 822 struct iriap_cb *self; 823 __u8 *frame; 824 __u8 opcode; 825 826 self = instance; 827 828 IRDA_ASSERT(skb != NULL, return 0;); 829 IRDA_ASSERT(self != NULL, goto out;); 830 IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;); 831 832 frame = skb->data; 833 834 if (self->mode == IAS_SERVER) { 835 /* Call server */ 836 pr_debug("%s(), Calling server!\n", __func__); 837 iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb); 838 goto out; 839 } 840 opcode = frame[0]; 841 if (~opcode & IAP_LST) { 842 net_warn_ratelimited("%s:, IrIAS multiframe commands or results is not implemented yet!\n", 843 __func__); 844 goto out; 845 } 846 847 /* Check for ack frames since they don't contain any data */ 848 if (opcode & IAP_ACK) { 849 pr_debug("%s() Got ack frame!\n", __func__); 850 goto out; 851 } 852 853 opcode &= ~IAP_LST; /* Mask away LST bit */ 854 855 switch (opcode) { 856 case GET_INFO_BASE: 857 pr_debug("IrLMP GetInfoBaseDetails not implemented!\n"); 858 break; 859 case GET_VALUE_BY_CLASS: 860 iriap_do_call_event(self, IAP_RECV_F_LST, NULL); 861 862 switch (frame[1]) { 863 case IAS_SUCCESS: 864 iriap_getvaluebyclass_confirm(self, skb); 865 break; 866 case IAS_CLASS_UNKNOWN: 867 pr_debug("%s(), No such class!\n", __func__); 868 /* Finished, close connection! */ 869 iriap_disconnect_request(self); 870 871 /* 872 * Warning, the client might close us, so remember 873 * no to use self anymore after calling confirm 874 */ 875 if (self->confirm) 876 self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, 877 self->priv); 878 break; 879 case IAS_ATTRIB_UNKNOWN: 880 pr_debug("%s(), No such attribute!\n", __func__); 881 /* Finished, close connection! */ 882 iriap_disconnect_request(self); 883 884 /* 885 * Warning, the client might close us, so remember 886 * no to use self anymore after calling confirm 887 */ 888 if (self->confirm) 889 self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL, 890 self->priv); 891 break; 892 } 893 break; 894 default: 895 pr_debug("%s(), Unknown op-code: %02x\n", __func__, 896 opcode); 897 break; 898 } 899 900 out: 901 /* Cleanup - sub-calls will have done skb_get() as needed. */ 902 dev_kfree_skb(skb); 903 return 0; 904 } 905 906 /* 907 * Function iriap_call_indication (self, skb) 908 * 909 * Received call to server from peer LM-IAS 910 * 911 */ 912 void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb) 913 { 914 __u8 *fp; 915 __u8 opcode; 916 917 IRDA_ASSERT(self != NULL, return;); 918 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 919 IRDA_ASSERT(skb != NULL, return;); 920 921 fp = skb->data; 922 923 opcode = fp[0]; 924 if (~opcode & 0x80) { 925 net_warn_ratelimited("%s: IrIAS multiframe commands or results is not implemented yet!\n", 926 __func__); 927 return; 928 } 929 opcode &= 0x7f; /* Mask away LST bit */ 930 931 switch (opcode) { 932 case GET_INFO_BASE: 933 net_warn_ratelimited("%s: GetInfoBaseDetails not implemented yet!\n", 934 __func__); 935 break; 936 case GET_VALUE_BY_CLASS: 937 iriap_getvaluebyclass_indication(self, skb); 938 break; 939 } 940 /* skb will be cleaned up in iriap_data_indication */ 941 } 942 943 /* 944 * Function iriap_watchdog_timer_expired (data) 945 * 946 * Query has taken too long time, so abort 947 * 948 */ 949 static void iriap_watchdog_timer_expired(void *data) 950 { 951 struct iriap_cb *self = (struct iriap_cb *) data; 952 953 IRDA_ASSERT(self != NULL, return;); 954 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 955 956 /* iriap_close(self); */ 957 } 958 959 #ifdef CONFIG_PROC_FS 960 961 static const char *const ias_value_types[] = { 962 "IAS_MISSING", 963 "IAS_INTEGER", 964 "IAS_OCT_SEQ", 965 "IAS_STRING" 966 }; 967 968 static inline struct ias_object *irias_seq_idx(loff_t pos) 969 { 970 struct ias_object *obj; 971 972 for (obj = (struct ias_object *) hashbin_get_first(irias_objects); 973 obj; obj = (struct ias_object *) hashbin_get_next(irias_objects)) { 974 if (pos-- == 0) 975 break; 976 } 977 978 return obj; 979 } 980 981 static void *irias_seq_start(struct seq_file *seq, loff_t *pos) 982 { 983 spin_lock_irq(&irias_objects->hb_spinlock); 984 985 return *pos ? irias_seq_idx(*pos - 1) : SEQ_START_TOKEN; 986 } 987 988 static void *irias_seq_next(struct seq_file *seq, void *v, loff_t *pos) 989 { 990 ++*pos; 991 992 return (v == SEQ_START_TOKEN) 993 ? (void *) hashbin_get_first(irias_objects) 994 : (void *) hashbin_get_next(irias_objects); 995 } 996 997 static void irias_seq_stop(struct seq_file *seq, void *v) 998 { 999 spin_unlock_irq(&irias_objects->hb_spinlock); 1000 } 1001 1002 static int irias_seq_show(struct seq_file *seq, void *v) 1003 { 1004 if (v == SEQ_START_TOKEN) 1005 seq_puts(seq, "LM-IAS Objects:\n"); 1006 else { 1007 struct ias_object *obj = v; 1008 struct ias_attrib *attrib; 1009 1010 IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -EINVAL;); 1011 1012 seq_printf(seq, "name: %s, id=%d\n", 1013 obj->name, obj->id); 1014 1015 /* Careful for priority inversions here ! 1016 * All other uses of attrib spinlock are independent of 1017 * the object spinlock, so we are safe. Jean II */ 1018 spin_lock(&obj->attribs->hb_spinlock); 1019 1020 /* List all attributes for this object */ 1021 for (attrib = (struct ias_attrib *) hashbin_get_first(obj->attribs); 1022 attrib != NULL; 1023 attrib = (struct ias_attrib *) hashbin_get_next(obj->attribs)) { 1024 1025 IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, 1026 goto outloop; ); 1027 1028 seq_printf(seq, " - Attribute name: \"%s\", ", 1029 attrib->name); 1030 seq_printf(seq, "value[%s]: ", 1031 ias_value_types[attrib->value->type]); 1032 1033 switch (attrib->value->type) { 1034 case IAS_INTEGER: 1035 seq_printf(seq, "%d\n", 1036 attrib->value->t.integer); 1037 break; 1038 case IAS_STRING: 1039 seq_printf(seq, "\"%s\"\n", 1040 attrib->value->t.string); 1041 break; 1042 case IAS_OCT_SEQ: 1043 seq_printf(seq, "octet sequence (%d bytes)\n", 1044 attrib->value->len); 1045 break; 1046 case IAS_MISSING: 1047 seq_puts(seq, "missing\n"); 1048 break; 1049 default: 1050 seq_printf(seq, "type %d?\n", 1051 attrib->value->type); 1052 } 1053 seq_putc(seq, '\n'); 1054 1055 } 1056 IRDA_ASSERT_LABEL(outloop:) 1057 spin_unlock(&obj->attribs->hb_spinlock); 1058 } 1059 1060 return 0; 1061 } 1062 1063 static const struct seq_operations irias_seq_ops = { 1064 .start = irias_seq_start, 1065 .next = irias_seq_next, 1066 .stop = irias_seq_stop, 1067 .show = irias_seq_show, 1068 }; 1069 1070 static int irias_seq_open(struct inode *inode, struct file *file) 1071 { 1072 IRDA_ASSERT( irias_objects != NULL, return -EINVAL;); 1073 1074 return seq_open(file, &irias_seq_ops); 1075 } 1076 1077 const struct file_operations irias_seq_fops = { 1078 .owner = THIS_MODULE, 1079 .open = irias_seq_open, 1080 .read = seq_read, 1081 .llseek = seq_lseek, 1082 .release = seq_release, 1083 }; 1084 1085 #endif /* PROC_FS */ 1086
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.