00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <linux/config.h>
00027 #include <linux/malloc.h>
00028 #include <linux/string.h>
00029 #include <linux/skbuff.h>
00030 #include <linux/types.h>
00031 #include <linux/proc_fs.h>
00032 #include <linux/init.h>
00033 #include <linux/kmod.h>
00034 #include <linux/random.h>
00035
00036 #include <net/irda/irda.h>
00037 #include <net/irda/irmod.h>
00038 #include <net/irda/timer.h>
00039 #include <net/irda/qos.h>
00040 #include <net/irda/irlap.h>
00041 #include <net/irda/iriap.h>
00042 #include <net/irda/irlmp.h>
00043 #include <net/irda/irlmp_frame.h>
00044
00045
00046 struct irlmp_cb *irlmp = NULL;
00047
00048
00049 int sysctl_discovery = 0;
00050 int sysctl_discovery_timeout = 3;
00051 int sysctl_discovery_slots = 6;
00052 char sysctl_devname[65];
00053
00054 char *lmp_reasons[] = {
00055 "ERROR, NOT USED",
00056 "LM_USER_REQUEST",
00057 "LM_LAP_DISCONNECT",
00058 "LM_CONNECT_FAILURE",
00059 "LM_LAP_RESET",
00060 "LM_INIT_DISCONNECT",
00061 "ERROR, NOT USED",
00062 };
00063
00064 __u8 *irlmp_hint_to_service(__u8 *hint);
00065 #ifdef CONFIG_PROC_FS
00066 int irlmp_proc_read(char *buf, char **start, off_t offst, int len, int unused);
00067 #endif
00068
00069
00070
00071
00072
00073
00074
00075 int __init irlmp_init(void)
00076 {
00077
00078 irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
00079 if (irlmp == NULL)
00080 return -ENOMEM;
00081 memset(irlmp, 0, sizeof(struct irlmp_cb));
00082
00083 irlmp->magic = LMP_MAGIC;
00084 spin_lock_init(&irlmp->lock);
00085
00086 irlmp->clients = hashbin_new(HB_GLOBAL);
00087 irlmp->services = hashbin_new(HB_GLOBAL);
00088 irlmp->links = hashbin_new(HB_GLOBAL);
00089 irlmp->unconnected_lsaps = hashbin_new(HB_GLOBAL);
00090 irlmp->cachelog = hashbin_new(HB_GLOBAL);
00091
00092 irlmp->free_lsap_sel = 0x10;
00093 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
00094 irlmp->cache.valid = FALSE;
00095 #endif
00096 strcpy(sysctl_devname, "Linux");
00097
00098
00099 init_timer(&irlmp->discovery_timer);
00100 irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout*HZ);
00101
00102 return 0;
00103 }
00104
00105
00106
00107
00108
00109
00110
00111 void irlmp_cleanup(void)
00112 {
00113
00114 ASSERT(irlmp != NULL, return;);
00115 ASSERT(irlmp->magic == LMP_MAGIC, return;);
00116
00117 del_timer(&irlmp->discovery_timer);
00118
00119 hashbin_delete(irlmp->links, (FREE_FUNC) kfree);
00120 hashbin_delete(irlmp->unconnected_lsaps, (FREE_FUNC) kfree);
00121 hashbin_delete(irlmp->clients, (FREE_FUNC) kfree);
00122 hashbin_delete(irlmp->services, (FREE_FUNC) kfree);
00123 hashbin_delete(irlmp->cachelog, (FREE_FUNC) kfree);
00124
00125
00126 kfree(irlmp);
00127 irlmp = NULL;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136 struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid)
00137 {
00138 struct lsap_cb *self;
00139
00140 ASSERT(notify != NULL, return NULL;);
00141 ASSERT(irlmp != NULL, return NULL;);
00142 ASSERT(irlmp->magic == LMP_MAGIC, return NULL;);
00143
00144
00145 if (slsap_sel == LSAP_ANY) {
00146 slsap_sel = irlmp_find_free_slsap();
00147 if (!slsap_sel)
00148 return NULL;
00149 } else if (irlmp_slsap_inuse(slsap_sel))
00150 return NULL;
00151
00152
00153 self = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
00154 if (self == NULL) {
00155 ERROR(__FUNCTION__ "(), can't allocate memory");
00156 return NULL;
00157 }
00158 memset(self, 0, sizeof(struct lsap_cb));
00159
00160 self->magic = LMP_LSAP_MAGIC;
00161 self->slsap_sel = slsap_sel;
00162
00163
00164 if (slsap_sel == LSAP_CONNLESS) {
00165 #ifdef CONFIG_IRDA_ULTRA
00166 self->dlsap_sel = LSAP_CONNLESS;
00167 self->pid = pid;
00168 #endif
00169 } else
00170 self->dlsap_sel = LSAP_ANY;
00171 self->connected = FALSE;
00172
00173 init_timer(&self->watchdog_timer);
00174
00175 ASSERT(notify->instance != NULL, return NULL;);
00176 self->notify = *notify;
00177
00178 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
00179
00180
00181 hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) self, (int) self,
00182 NULL);
00183
00184 return self;
00185 }
00186
00187
00188
00189
00190
00191
00192 static void __irlmp_close_lsap(struct lsap_cb *self)
00193 {
00194 IRDA_DEBUG(4, __FUNCTION__ "()\n");
00195
00196 ASSERT(self != NULL, return;);
00197 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
00198
00199
00200
00201
00202 self->magic = 0;
00203 del_timer(&self->watchdog_timer);
00204
00205 if (self->conn_skb)
00206 dev_kfree_skb(self->conn_skb);
00207
00208 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
00209 ASSERT(irlmp != NULL, return;);
00210 irlmp->cache.valid = FALSE;
00211 #endif
00212 kfree(self);
00213 }
00214
00215
00216
00217
00218
00219
00220
00221 void irlmp_close_lsap(struct lsap_cb *self)
00222 {
00223 struct lap_cb *lap;
00224 struct lsap_cb *lsap = NULL;
00225
00226 ASSERT(self != NULL, return;);
00227 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
00228
00229
00230
00231
00232
00233 lap = self->lap;
00234 if (lap) {
00235 ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
00236 lsap = hashbin_remove(lap->lsaps, (int) self, NULL);
00237 }
00238
00239 if (!lsap) {
00240 lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self,
00241 NULL);
00242 }
00243 if (!lsap) {
00244 IRDA_DEBUG(0, __FUNCTION__
00245 "(), Looks like somebody has removed me already!\n");
00246 return;
00247 }
00248 __irlmp_close_lsap(self);
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258 void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify)
00259 {
00260 struct lap_cb *lap;
00261
00262 ASSERT(irlmp != NULL, return;);
00263 ASSERT(irlmp->magic == LMP_MAGIC, return;);
00264 ASSERT(notify != NULL, return;);
00265
00266
00267
00268
00269 lap = kmalloc(sizeof(struct lap_cb), GFP_KERNEL);
00270 if (lap == NULL) {
00271 ERROR(__FUNCTION__ "(), unable to kmalloc\n");
00272 return;
00273 }
00274 memset(lap, 0, sizeof(struct lap_cb));
00275
00276 lap->irlap = irlap;
00277 lap->magic = LMP_LAP_MAGIC;
00278 lap->saddr = saddr;
00279 lap->daddr = DEV_ADDR_ANY;
00280 lap->lsaps = hashbin_new(HB_GLOBAL);
00281
00282 irlmp_next_lap_state(lap, LAP_STANDBY);
00283
00284 init_timer(&lap->idle_timer);
00285
00286
00287
00288
00289 hashbin_insert(irlmp->links, (queue_t *) lap, lap->saddr, NULL);
00290
00291
00292
00293
00294
00295 irda_notify_init(notify);
00296 notify->instance = lap;
00297 }
00298
00299
00300
00301
00302
00303
00304
00305 void irlmp_unregister_link(__u32 saddr)
00306 {
00307 struct lap_cb *link;
00308
00309 IRDA_DEBUG(4, __FUNCTION__ "()\n");
00310
00311 link = hashbin_remove(irlmp->links, saddr, NULL);
00312 if (link) {
00313 ASSERT(link->magic == LMP_LAP_MAGIC, return;);
00314
00315
00316 irlmp_expire_discoveries(irlmp->cachelog, link->saddr, TRUE);
00317
00318 del_timer(&link->idle_timer);
00319
00320 link->magic = 0;
00321 kfree(link);
00322 }
00323 }
00324
00325
00326
00327
00328
00329
00330
00331 int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
00332 __u32 saddr, __u32 daddr,
00333 struct qos_info *qos, struct sk_buff *userdata)
00334 {
00335 struct sk_buff *skb = NULL;
00336 struct lap_cb *lap;
00337 struct lsap_cb *lsap;
00338 discovery_t *discovery;
00339
00340 ASSERT(self != NULL, return -EBADR;);
00341 ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
00342
00343 IRDA_DEBUG(2, __FUNCTION__
00344 "(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
00345 self->slsap_sel, dlsap_sel, saddr, daddr);
00346
00347 if (self->connected)
00348 return -EISCONN;
00349
00350
00351 if (!daddr)
00352 return -EINVAL;
00353
00354
00355 if (userdata == NULL) {
00356 skb = dev_alloc_skb(64);
00357 if (!skb)
00358 return -ENOMEM;
00359
00360 skb_reserve(skb, LMP_MAX_HEADER);
00361 } else
00362 skb = userdata;
00363
00364
00365 ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;);
00366 skb_push(skb, LMP_CONTROL_HEADER);
00367
00368 self->dlsap_sel = dlsap_sel;
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 if (!saddr) {
00379 if (daddr != DEV_ADDR_ANY)
00380 discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
00381 else {
00382 IRDA_DEBUG(2, __FUNCTION__ "(), no daddr\n");
00383 discovery = (discovery_t *)
00384 hashbin_get_first(irlmp->cachelog);
00385 }
00386
00387 if (discovery) {
00388 saddr = discovery->saddr;
00389 daddr = discovery->daddr;
00390 }
00391 }
00392 lap = hashbin_find(irlmp->links, saddr, NULL);
00393 if (lap == NULL) {
00394 IRDA_DEBUG(1, __FUNCTION__ "(), Unable to find a usable link!\n");
00395 return -EHOSTUNREACH;
00396 }
00397
00398 if (lap->daddr == DEV_ADDR_ANY)
00399 lap->daddr = daddr;
00400 else if (lap->daddr != daddr) {
00401 IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but link is busy!\n");
00402 return -EBUSY;
00403 }
00404
00405 self->lap = lap;
00406
00407
00408
00409
00410
00411 lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, NULL);
00412
00413 ASSERT(lsap != NULL, return -1;);
00414 ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
00415 ASSERT(lsap->lap != NULL, return -1;);
00416 ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
00417
00418 hashbin_insert(self->lap->lsaps, (queue_t *) self, (int) self, NULL);
00419
00420 self->connected = TRUE;
00421
00422
00423
00424
00425 if (qos)
00426 self->qos = *qos;
00427
00428 irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, skb);
00429
00430 return 0;
00431 }
00432
00433
00434
00435
00436
00437
00438
00439 void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
00440 {
00441 int max_seg_size;
00442 int lap_header_size;
00443 int max_header_size;
00444
00445 ASSERT(self != NULL, return;);
00446 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
00447 ASSERT(skb != NULL, return;);
00448 ASSERT(self->lap != NULL, return;);
00449
00450 IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
00451 self->slsap_sel, self->dlsap_sel);
00452
00453 self->qos = *self->lap->qos;
00454
00455 max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
00456 lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
00457 max_header_size = LMP_HEADER + lap_header_size;
00458
00459
00460 skb_pull(skb, LMP_CONTROL_HEADER);
00461
00462 if (self->notify.connect_indication)
00463 self->notify.connect_indication(self->notify.instance, self,
00464 &self->qos, max_seg_size,
00465 max_header_size, skb);
00466 }
00467
00468
00469
00470
00471
00472
00473
00474 int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
00475 {
00476 struct sk_buff *skb;
00477
00478 ASSERT(self != NULL, return -1;);
00479 ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
00480
00481
00482 if (!userdata) {
00483 skb = dev_alloc_skb(64);
00484 if (!skb)
00485 return -ENOMEM;
00486
00487
00488 skb_reserve(skb, LMP_MAX_HEADER);
00489 } else {
00490 skb = userdata;
00491
00492
00493
00494
00495 ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;);
00496 }
00497
00498 self->connected = TRUE;
00499
00500 IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
00501 self->slsap_sel, self->dlsap_sel);
00502
00503
00504 skb_push(skb, LMP_CONTROL_HEADER);
00505 irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, skb);
00506
00507 return 0;
00508 }
00509
00510
00511
00512
00513
00514
00515 void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
00516 {
00517 int max_header_size;
00518 int lap_header_size;
00519 int max_seg_size;
00520
00521 IRDA_DEBUG(3, __FUNCTION__ "()\n");
00522
00523 ASSERT(skb != NULL, return;);
00524 ASSERT(self != NULL, return;);
00525 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
00526 ASSERT(self->lap != NULL, return;);
00527
00528 self->qos = *self->lap->qos;
00529
00530 max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
00531 lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
00532 max_header_size = LMP_HEADER + lap_header_size;
00533
00534 IRDA_DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n",
00535 max_header_size);
00536
00537
00538 skb_pull(skb, LMP_CONTROL_HEADER);
00539
00540 if (self->notify.connect_confirm) {
00541 self->notify.connect_confirm(self->notify.instance, self,
00542 &self->qos, max_seg_size,
00543 max_header_size, skb);
00544 }
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554 struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
00555 {
00556 struct lsap_cb *new;
00557
00558 IRDA_DEBUG(1, __FUNCTION__ "()\n");
00559
00560
00561 if (!hashbin_find(irlmp->unconnected_lsaps, (int) orig, NULL)) {
00562 IRDA_DEBUG(0, __FUNCTION__ "(), unable to find LSAP\n");
00563 return NULL;
00564 }
00565 new = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
00566 if (!new) {
00567 IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
00568 return NULL;
00569 }
00570
00571 memcpy(new, orig, sizeof(struct lsap_cb));
00572 new->notify.instance = instance;
00573
00574 init_timer(&new->watchdog_timer);
00575
00576 hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) new, (int) new,
00577 NULL);
00578
00579
00580 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
00581 irlmp->cache.valid = FALSE;
00582 #endif
00583
00584 return new;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593 int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
00594 {
00595 struct lsap_cb *lsap;
00596
00597 ASSERT(self != NULL, return -1;);
00598 ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
00599
00600
00601 if (!self->connected) {
00602 WARNING(__FUNCTION__ "(), already disconnected!\n");
00603 return -1;
00604 }
00605
00606 ASSERT(userdata != NULL, return -1;);
00607 ASSERT(self->connected == TRUE, return -1;);
00608
00609 skb_push(userdata, LMP_CONTROL_HEADER);
00610
00611
00612
00613
00614
00615 irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata);
00616
00617
00618
00619
00620
00621 ASSERT(self->lap != NULL, return -1;);
00622 ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
00623 ASSERT(self->lap->lsaps != NULL, return -1;);
00624
00625 lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
00626
00627 ASSERT(lsap != NULL, return -1;);
00628 ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
00629 ASSERT(lsap == self, return -1;);
00630
00631 hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) self, (int) self,
00632 NULL);
00633
00634
00635 self->connected = FALSE;
00636 self->dlsap_sel = LSAP_ANY;
00637 self->lap = NULL;
00638
00639 return 0;
00640 }
00641
00642
00643
00644
00645
00646
00647 void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
00648 struct sk_buff *userdata)
00649 {
00650 struct lsap_cb *lsap;
00651
00652 IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);
00653 ASSERT(self != NULL, return;);
00654 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
00655 ASSERT(self->connected == TRUE, return;);
00656
00657 IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
00658 self->slsap_sel, self->dlsap_sel);
00659
00660 self->connected = FALSE;
00661 self->dlsap_sel = LSAP_ANY;
00662
00663 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
00664 irlmp->cache.valid = FALSE;
00665 #endif
00666
00667
00668
00669
00670 ASSERT(self->lap != NULL, return;);
00671 ASSERT(self->lap->lsaps != NULL, return;);
00672
00673 lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
00674
00675 ASSERT(lsap != NULL, return;);
00676 ASSERT(lsap == self, return;);
00677 hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) lsap, (int) lsap,
00678 NULL);
00679
00680 self->lap = NULL;
00681
00682
00683
00684
00685 if (self->notify.disconnect_indication)
00686 self->notify.disconnect_indication(self->notify.instance,
00687 self, reason, userdata);
00688 else {
00689 IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n");
00690 dev_kfree_skb(userdata);
00691 }
00692 }
00693
00694
00695
00696
00697
00698
00699
00700 void irlmp_do_discovery(int nslots)
00701 {
00702 struct lap_cb *lap;
00703
00704
00705 if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
00706 WARNING(__FUNCTION__
00707 "(), invalid value for number of slots!\n");
00708 nslots = sysctl_discovery_slots = 8;
00709 }
00710
00711
00712 irlmp->discovery_cmd.hints.word = irlmp->hints.word;
00713
00714
00715
00716
00717
00718
00719 irlmp->discovery_cmd.charset = CS_ASCII;
00720 strncpy(irlmp->discovery_cmd.nickname, sysctl_devname,
00721 NICKNAME_MAX_LEN);
00722 irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.nickname);
00723 irlmp->discovery_cmd.nslots = nslots;
00724
00725
00726
00727
00728 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
00729 while (lap != NULL) {
00730 ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
00731
00732 if (lap->lap_state == LAP_STANDBY) {
00733
00734 irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,
00735 FALSE);
00736
00737
00738 irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST,
00739 NULL);
00740 }
00741 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
00742 }
00743 }
00744
00745
00746
00747
00748
00749
00750
00751 void irlmp_discovery_request(int nslots)
00752 {
00753
00754 if (nslots == DISCOVERY_DEFAULT_SLOTS)
00755 nslots = sysctl_discovery_slots;
00756
00757
00758 irlmp_discovery_confirm(irlmp->cachelog);
00759
00760
00761
00762
00763
00764 if (!sysctl_discovery)
00765 irlmp_do_discovery(nslots);
00766 }
00767
00768 #if 0
00769
00770
00771
00772
00773
00774
00775 void irlmp_check_services(discovery_t *discovery)
00776 {
00777 struct irlmp_client *client;
00778 struct irmanager_event event;
00779 __u8 *service_log;
00780 __u8 service;
00781 int i = 0;
00782
00783 IRDA_DEBUG(1, "IrDA Discovered: %s\n", discovery->info);
00784 IRDA_DEBUG(1, " Services: ");
00785
00786 service_log = irlmp_hint_to_service(discovery->hints.byte);
00787 if (!service_log)
00788 return;
00789
00790
00791
00792
00793 while ((service = service_log[i++]) != S_END) {
00794 IRDA_DEBUG( 4, "service=%02x\n", service);
00795 client = hashbin_find(irlmp->registry, service, NULL);
00796 if (entry && entry->discovery_callback) {
00797 IRDA_DEBUG( 4, "discovery_callback!\n");
00798
00799 entry->discovery_callback(discovery);
00800 } else {
00801
00802 if (service == S_ANY)
00803 continue;
00804
00805
00806
00807
00808
00809 event.event = EVENT_DEVICE_DISCOVERED;
00810 event.service = service;
00811 event.daddr = discovery->daddr;
00812 sprintf(event.info, "%s", discovery->info);
00813 irmanager_notify(&event);
00814 }
00815 }
00816 kfree(service_log);
00817 }
00818 #endif
00819
00820
00821
00822
00823
00824
00825 void irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
00826 {
00827 discovery_t *discovery;
00828
00829 IRDA_DEBUG(3, __FUNCTION__ "()\n");
00830
00831
00832 if (client->callback2)
00833 client->callback2(log);
00834
00835
00836
00837
00838
00839 discovery = (discovery_t *) hashbin_get_first(log);
00840 while (discovery != NULL) {
00841 IRDA_DEBUG(3, "discovery->daddr = 0x%08x\n", discovery->daddr);
00842
00843
00844
00845
00846
00847 if (client->hint_mask & discovery->hints.word & 0x7f7f) {
00848 if (client->callback1)
00849 client->callback1(discovery);
00850 }
00851 discovery = (discovery_t *) hashbin_get_next(log);
00852 }
00853 }
00854
00855
00856
00857
00858
00859
00860
00861
00862 void irlmp_discovery_confirm(hashbin_t *log)
00863 {
00864 irlmp_client_t *client;
00865
00866 IRDA_DEBUG(3, __FUNCTION__ "()\n");
00867
00868 ASSERT(log != NULL, return;);
00869
00870 if (!(HASHBIN_GET_SIZE(log)))
00871 return;
00872
00873 client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
00874 while (client != NULL) {
00875
00876 irlmp_notify_client(client, log);
00877
00878 client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
00879 }
00880 }
00881
00882
00883
00884
00885
00886
00887
00888 discovery_t *irlmp_get_discovery_response()
00889 {
00890 IRDA_DEBUG(4, __FUNCTION__ "()\n");
00891
00892 ASSERT(irlmp != NULL, return NULL;);
00893
00894 irlmp->discovery_rsp.hints.word = irlmp->hints.word;
00895
00896
00897
00898
00899
00900
00901 irlmp->discovery_rsp.charset = CS_ASCII;
00902
00903 strncpy(irlmp->discovery_rsp.nickname, sysctl_devname,
00904 NICKNAME_MAX_LEN);
00905 irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.nickname);
00906
00907 return &irlmp->discovery_rsp;
00908 }
00909
00910
00911
00912
00913
00914
00915
00916 int irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb)
00917 {
00918 ASSERT(self != NULL, return -1;);
00919 ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
00920
00921
00922 ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
00923 skb_push(skb, LMP_HEADER);
00924
00925 return irlmp_do_lsap_event(self, LM_DATA_REQUEST, skb);
00926 }
00927
00928
00929
00930
00931
00932
00933
00934 void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
00935 {
00936
00937 skb_pull(skb, LMP_HEADER);
00938
00939 if (self->notify.data_indication)
00940 self->notify.data_indication(self->notify.instance, self, skb);
00941 else
00942 dev_kfree_skb(skb);
00943 }
00944
00945
00946
00947
00948
00949
00950
00951 int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb)
00952 {
00953 IRDA_DEBUG(4, __FUNCTION__ "()\n");
00954
00955 ASSERT(skb != NULL, return -1;);
00956
00957
00958 ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
00959 skb_push(skb, LMP_HEADER);
00960
00961 return irlmp_do_lsap_event(self, LM_UDATA_REQUEST, skb);
00962 }
00963
00964
00965
00966
00967
00968
00969
00970 void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
00971 {
00972 IRDA_DEBUG(4, __FUNCTION__ "()\n");
00973
00974 ASSERT(self != NULL, return;);
00975 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
00976 ASSERT(skb != NULL, return;);
00977
00978
00979 skb_pull(skb, LMP_HEADER);
00980
00981 if (self->notify.udata_indication)
00982 self->notify.udata_indication(self->notify.instance, self,
00983 skb);
00984 else
00985 dev_kfree_skb(skb);
00986 }
00987
00988
00989
00990
00991
00992
00993
00994 #ifdef CONFIG_IRDA_ULTRA
00995 int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *skb)
00996 {
00997 struct sk_buff *clone_skb;
00998 struct lap_cb *lap;
00999
01000 IRDA_DEBUG(4, __FUNCTION__ "()\n");
01001
01002 ASSERT(skb != NULL, return -1;);
01003
01004
01005 ASSERT(skb_headroom(skb) >= LMP_HEADER+LMP_PID_HEADER, return -1;);
01006
01007
01008 skb_push(skb, LMP_PID_HEADER);
01009 skb->data[0] = self->pid;
01010
01011
01012 skb_push(skb, LMP_HEADER);
01013 skb->data[0] = skb->data[1] = LSAP_CONNLESS;
01014
01015
01016 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
01017 while (lap != NULL) {
01018 ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
01019
01020 clone_skb = skb_clone(skb, GFP_ATOMIC);
01021 if (!clone_skb)
01022 return -ENOMEM;
01023
01024 irlap_unitdata_request(lap->irlap, clone_skb);
01025
01026 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
01027 }
01028 dev_kfree_skb(skb);
01029
01030 return 0;
01031 }
01032 #endif
01033
01034
01035
01036
01037
01038
01039
01040 #ifdef CONFIG_IRDA_ULTRA
01041 void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
01042 {
01043 IRDA_DEBUG(4, __FUNCTION__ "()\n");
01044
01045 ASSERT(self != NULL, return;);
01046 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
01047 ASSERT(skb != NULL, return;);
01048
01049
01050 skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
01051
01052 if (self->notify.udata_indication)
01053 self->notify.udata_indication(self->notify.instance, self,
01054 skb);
01055 else
01056 dev_kfree_skb(skb);
01057 }
01058 #endif
01059
01060 void irlmp_status_request(void)
01061 {
01062 IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
01063 }
01064
01065 void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock)
01066 {
01067 IRDA_DEBUG(1, __FUNCTION__ "(), Not implemented\n");
01068 }
01069
01070
01071
01072
01073
01074
01075
01076 __u8 *irlmp_hint_to_service(__u8 *hint)
01077 {
01078 __u8 *service;
01079 int i = 0;
01080
01081
01082
01083
01084
01085 service = kmalloc(16, GFP_ATOMIC);
01086 if (!service) {
01087 IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
01088 return NULL;
01089 }
01090
01091 if (!hint[0]) {
01092 IRDA_DEBUG(1, "<None>\n");
01093 kfree(service);
01094 return NULL;
01095 }
01096 if (hint[0] & HINT_PNP)
01097 IRDA_DEBUG(1, "PnP Compatible ");
01098 if (hint[0] & HINT_PDA)
01099 IRDA_DEBUG(1, "PDA/Palmtop ");
01100 if (hint[0] & HINT_COMPUTER)
01101 IRDA_DEBUG(1, "Computer ");
01102 if (hint[0] & HINT_PRINTER) {
01103 IRDA_DEBUG(1, "Printer ");
01104 service[i++] = S_PRINTER;
01105 }
01106 if (hint[0] & HINT_MODEM)
01107 IRDA_DEBUG(1, "Modem ");
01108 if (hint[0] & HINT_FAX)
01109 IRDA_DEBUG(1, "Fax ");
01110 if (hint[0] & HINT_LAN) {
01111 IRDA_DEBUG(1, "LAN Access ");
01112 service[i++] = S_LAN;
01113 }
01114
01115
01116
01117
01118
01119 if (hint[0] & HINT_EXTENSION) {
01120 if (hint[1] & HINT_TELEPHONY) {
01121 IRDA_DEBUG(1, "Telephony ");
01122 service[i++] = S_TELEPHONY;
01123 } if (hint[1] & HINT_FILE_SERVER)
01124 IRDA_DEBUG(1, "File Server ");
01125
01126 if (hint[1] & HINT_COMM) {
01127 IRDA_DEBUG(1, "IrCOMM ");
01128 service[i++] = S_COMM;
01129 }
01130 if (hint[1] & HINT_OBEX) {
01131 IRDA_DEBUG(1, "IrOBEX ");
01132 service[i++] = S_OBEX;
01133 }
01134 }
01135 IRDA_DEBUG(1, "\n");
01136
01137
01138 service[i++] = S_ANY;
01139
01140 service[i] = S_END;
01141
01142 return service;
01143 }
01144
01145
01146
01147
01148
01149
01150
01151
01152 __u16 irlmp_service_to_hint(int service)
01153 {
01154 __u16_host_order hint;
01155
01156 hint.word = 0;
01157
01158 switch (service) {
01159 case S_PNP:
01160 hint.byte[0] |= HINT_PNP;
01161 break;
01162 case S_PDA:
01163 hint.byte[0] |= HINT_PDA;
01164 break;
01165 case S_COMPUTER:
01166 hint.byte[0] |= HINT_COMPUTER;
01167 break;
01168 case S_PRINTER:
01169 hint.byte[0] |= HINT_PRINTER;
01170 break;
01171 case S_MODEM:
01172 hint.byte[0] |= HINT_PRINTER;
01173 break;
01174 case S_LAN:
01175 hint.byte[0] |= HINT_LAN;
01176 break;
01177 case S_COMM:
01178 hint.byte[0] |= HINT_EXTENSION;
01179 hint.byte[1] |= HINT_COMM;
01180 break;
01181 case S_OBEX:
01182 hint.byte[0] |= HINT_EXTENSION;
01183 hint.byte[1] |= HINT_OBEX;
01184 break;
01185 case S_TELEPHONY:
01186 hint.byte[0] |= HINT_EXTENSION;
01187 hint.byte[1] |= HINT_TELEPHONY;
01188 break;
01189 case S_ANY:
01190 hint.word = 0xffff;
01191 break;
01192 default:
01193 IRDA_DEBUG( 1, __FUNCTION__ "(), Unknown service!\n");
01194 break;
01195 }
01196 return hint.word;
01197 }
01198
01199
01200
01201
01202
01203
01204
01205 __u32 irlmp_register_service(__u16 hints)
01206 {
01207 irlmp_service_t *service;
01208 __u32 handle;
01209
01210 IRDA_DEBUG(4, __FUNCTION__ "(), hints = %04x\n", hints);
01211
01212
01213 get_random_bytes(&handle, sizeof(handle));
01214 while (hashbin_find(irlmp->services, handle, NULL) || !handle)
01215 get_random_bytes(&handle, sizeof(handle));
01216
01217 irlmp->hints.word |= hints;
01218
01219
01220 service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
01221 if (!service) {
01222 IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
01223 return 0;
01224 }
01225 service->hints = hints;
01226 hashbin_insert(irlmp->services, (queue_t *) service, handle, NULL);
01227
01228 return handle;
01229 }
01230
01231
01232
01233
01234
01235
01236
01237
01238 int irlmp_unregister_service(__u32 handle)
01239 {
01240 irlmp_service_t *service;
01241
01242 IRDA_DEBUG(4, __FUNCTION__ "()\n");
01243
01244 if (!handle)
01245 return -1;
01246
01247 service = hashbin_find(irlmp->services, handle, NULL);
01248 if (!service) {
01249 IRDA_DEBUG(1, __FUNCTION__ "(), Unknown service!\n");
01250 return -1;
01251 }
01252
01253 service = hashbin_remove(irlmp->services, handle, NULL);
01254 if (service)
01255 kfree(service);
01256
01257
01258 irlmp->hints.word = 0;
01259
01260
01261 service = (irlmp_service_t *) hashbin_get_first(irlmp->services);
01262 while (service) {
01263 irlmp->hints.word |= service->hints;
01264
01265 service = (irlmp_service_t *)hashbin_get_next(irlmp->services);
01266 }
01267 return 0;
01268 }
01269
01270
01271
01272
01273
01274
01275
01276
01277 __u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 callback1,
01278 DISCOVERY_CALLBACK2 callback2)
01279 {
01280 irlmp_client_t *client;
01281 __u32 handle;
01282
01283
01284 get_random_bytes(&handle, sizeof(handle));
01285 while (hashbin_find(irlmp->clients, handle, NULL) || !handle)
01286 get_random_bytes(&handle, sizeof(handle));
01287
01288
01289 client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
01290 if (!client) {
01291 IRDA_DEBUG( 1, __FUNCTION__ "(), Unable to kmalloc!\n");
01292
01293 return 0;
01294 }
01295
01296
01297 client->hint_mask = hint_mask;
01298 client->callback1 = callback1;
01299 client->callback2 = callback2;
01300
01301 hashbin_insert(irlmp->clients, (queue_t *) client, handle, NULL);
01302
01303 return handle;
01304 }
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314 int irlmp_update_client(__u32 handle, __u16 hint_mask,
01315 DISCOVERY_CALLBACK1 callback1,
01316 DISCOVERY_CALLBACK2 callback2)
01317 {
01318 irlmp_client_t *client;
01319
01320 if (!handle)
01321 return -1;
01322
01323 client = hashbin_find(irlmp->clients, handle, NULL);
01324 if (!client) {
01325 IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
01326 return -1;
01327 }
01328
01329 client->hint_mask = hint_mask;
01330 client->callback1 = callback1;
01331 client->callback2 = callback2;
01332
01333 return 0;
01334 }
01335
01336
01337
01338
01339
01340
01341
01342 int irlmp_unregister_client(__u32 handle)
01343 {
01344 struct irlmp_client *client;
01345
01346 IRDA_DEBUG(4, __FUNCTION__ "()\n");
01347
01348 if (!handle)
01349 return -1;
01350
01351 client = hashbin_find(irlmp->clients, handle, NULL);
01352 if (!client) {
01353 IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
01354