Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * IrNET protocol module : Synchronous PPP over an IrDA socket. | |
3 | * | |
4 | * Jean II - HPL `00 - <jt@hpl.hp.com> | |
5 | * | |
6 | * This file implement the IRDA interface of IrNET. | |
7 | * Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly, | |
8 | * and exchange frames with IrTTP. | |
9 | */ | |
10 | ||
11 | #include "irnet_irda.h" /* Private header */ | |
12 | ||
13 | /************************* CONTROL CHANNEL *************************/ | |
14 | /* | |
15 | * When ppp is not active, /dev/irnet act as a control channel. | |
16 | * Writing allow to set up the IrDA destination of the IrNET channel, | |
17 | * and any application may be read events happening on IrNET... | |
18 | */ | |
19 | ||
20 | /*------------------------------------------------------------------*/ | |
21 | /* | |
22 | * Post an event to the control channel... | |
23 | * Put the event in the log, and then wait all process blocked on read | |
24 | * so they can read the log... | |
25 | */ | |
26 | static void | |
27 | irnet_post_event(irnet_socket * ap, | |
28 | irnet_event event, | |
29 | __u32 saddr, | |
30 | __u32 daddr, | |
31 | char * name, | |
32 | __u16 hints) | |
33 | { | |
34 | int index; /* In the log */ | |
35 | ||
36 | DENTER(CTRL_TRACE, "(ap=0x%p, event=%d, daddr=%08x, name=``%s'')\n", | |
37 | ap, event, daddr, name); | |
38 | ||
39 | /* Protect this section via spinlock. | |
40 | * Note : as we are the only event producer, we only need to exclude | |
41 | * ourself when touching the log, which is nice and easy. | |
42 | */ | |
43 | spin_lock_bh(&irnet_events.spinlock); | |
44 | ||
45 | /* Copy the event in the log */ | |
46 | index = irnet_events.index; | |
47 | irnet_events.log[index].event = event; | |
48 | irnet_events.log[index].daddr = daddr; | |
49 | irnet_events.log[index].saddr = saddr; | |
50 | /* Try to copy IrDA nickname */ | |
51 | if(name) | |
52 | strcpy(irnet_events.log[index].name, name); | |
53 | else | |
54 | irnet_events.log[index].name[0] = '\0'; | |
55 | /* Copy hints */ | |
56 | irnet_events.log[index].hints.word = hints; | |
57 | /* Try to get ppp unit number */ | |
58 | if((ap != (irnet_socket *) NULL) && (ap->ppp_open)) | |
59 | irnet_events.log[index].unit = ppp_unit_number(&ap->chan); | |
60 | else | |
61 | irnet_events.log[index].unit = -1; | |
62 | ||
63 | /* Increment the index | |
64 | * Note that we increment the index only after the event is written, | |
65 | * to make sure that the readers don't get garbage... */ | |
66 | irnet_events.index = (index + 1) % IRNET_MAX_EVENTS; | |
67 | ||
68 | DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index); | |
69 | ||
70 | /* Spin lock end */ | |
71 | spin_unlock_bh(&irnet_events.spinlock); | |
72 | ||
73 | /* Now : wake up everybody waiting for events... */ | |
74 | wake_up_interruptible_all(&irnet_events.rwait); | |
75 | ||
76 | DEXIT(CTRL_TRACE, "\n"); | |
77 | } | |
78 | ||
79 | /************************* IRDA SUBROUTINES *************************/ | |
80 | /* | |
81 | * These are a bunch of subroutines called from other functions | |
82 | * down there, mostly common code or to improve readability... | |
83 | * | |
84 | * Note : we duplicate quite heavily some routines of af_irda.c, | |
85 | * because our input structure (self) is quite different | |
86 | * (struct irnet instead of struct irda_sock), which make sharing | |
87 | * the same code impossible (at least, without templates). | |
88 | */ | |
89 | ||
90 | /*------------------------------------------------------------------*/ | |
91 | /* | |
92 | * Function irda_open_tsap (self) | |
93 | * | |
94 | * Open local Transport Service Access Point (TSAP) | |
95 | * | |
96 | * Create a IrTTP instance for us and set all the IrTTP callbacks. | |
97 | */ | |
98 | static inline int | |
99 | irnet_open_tsap(irnet_socket * self) | |
100 | { | |
101 | notify_t notify; /* Callback structure */ | |
102 | ||
103 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | |
104 | ||
105 | DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n"); | |
106 | ||
107 | /* Initialize IrTTP callbacks to be used by the IrDA stack */ | |
108 | irda_notify_init(¬ify); | |
109 | notify.connect_confirm = irnet_connect_confirm; | |
110 | notify.connect_indication = irnet_connect_indication; | |
111 | notify.disconnect_indication = irnet_disconnect_indication; | |
112 | notify.data_indication = irnet_data_indication; | |
113 | /*notify.udata_indication = NULL;*/ | |
114 | notify.flow_indication = irnet_flow_indication; | |
115 | notify.status_indication = irnet_status_indication; | |
116 | notify.instance = self; | |
117 | strlcpy(notify.name, IRNET_NOTIFY_NAME, sizeof(notify.name)); | |
118 | ||
119 | /* Open an IrTTP instance */ | |
120 | self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, | |
121 | ¬ify); | |
122 | DABORT(self->tsap == NULL, -ENOMEM, | |
123 | IRDA_SR_ERROR, "Unable to allocate TSAP !\n"); | |
124 | ||
125 | /* Remember which TSAP selector we actually got */ | |
126 | self->stsap_sel = self->tsap->stsap_sel; | |
127 | ||
128 | DEXIT(IRDA_SR_TRACE, " - tsap=0x%p, sel=0x%X\n", | |
129 | self->tsap, self->stsap_sel); | |
130 | return 0; | |
131 | } | |
132 | ||
133 | /*------------------------------------------------------------------*/ | |
134 | /* | |
135 | * Function irnet_ias_to_tsap (self, result, value) | |
136 | * | |
137 | * Examine an IAS object and extract TSAP | |
138 | * | |
139 | * We do an IAP query to find the TSAP associated with the IrNET service. | |
140 | * When IrIAP pass us the result of the query, this function look at | |
141 | * the return values to check for failures and extract the TSAP if | |
142 | * possible. | |
143 | * Also deallocate value | |
144 | * The failure is in self->errno | |
145 | * Return TSAP or -1 | |
146 | */ | |
147 | static inline __u8 | |
148 | irnet_ias_to_tsap(irnet_socket * self, | |
149 | int result, | |
150 | struct ias_value * value) | |
151 | { | |
152 | __u8 dtsap_sel = 0; /* TSAP we are looking for */ | |
153 | ||
154 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | |
155 | ||
156 | /* By default, no error */ | |
157 | self->errno = 0; | |
158 | ||
159 | /* Check if request succeeded */ | |
160 | switch(result) | |
161 | { | |
162 | /* Standard errors : service not available */ | |
163 | case IAS_CLASS_UNKNOWN: | |
164 | case IAS_ATTRIB_UNKNOWN: | |
165 | DEBUG(IRDA_SR_INFO, "IAS object doesn't exist ! (%d)\n", result); | |
166 | self->errno = -EADDRNOTAVAIL; | |
167 | break; | |
168 | ||
169 | /* Other errors, most likely IrDA stack failure */ | |
170 | default : | |
171 | DEBUG(IRDA_SR_INFO, "IAS query failed ! (%d)\n", result); | |
172 | self->errno = -EHOSTUNREACH; | |
173 | break; | |
174 | ||
175 | /* Success : we got what we wanted */ | |
176 | case IAS_SUCCESS: | |
177 | break; | |
178 | } | |
179 | ||
180 | /* Check what was returned to us */ | |
181 | if(value != NULL) | |
182 | { | |
183 | /* What type of argument have we got ? */ | |
184 | switch(value->type) | |
185 | { | |
186 | case IAS_INTEGER: | |
187 | DEBUG(IRDA_SR_INFO, "result=%d\n", value->t.integer); | |
188 | if(value->t.integer != -1) | |
189 | /* Get the remote TSAP selector */ | |
190 | dtsap_sel = value->t.integer; | |
191 | else | |
192 | self->errno = -EADDRNOTAVAIL; | |
193 | break; | |
194 | default: | |
195 | self->errno = -EADDRNOTAVAIL; | |
196 | DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", value->type); | |
197 | break; | |
198 | } | |
199 | ||
200 | /* Cleanup */ | |
201 | irias_delete_value(value); | |
202 | } | |
203 | else /* value == NULL */ | |
204 | { | |
205 | /* Nothing returned to us - usually result != SUCCESS */ | |
206 | if(!(self->errno)) | |
207 | { | |
208 | DERROR(IRDA_SR_ERROR, | |
209 | "IrDA bug : result == SUCCESS && value == NULL\n"); | |
210 | self->errno = -EHOSTUNREACH; | |
211 | } | |
212 | } | |
213 | DEXIT(IRDA_SR_TRACE, "\n"); | |
214 | ||
215 | /* Return the TSAP */ | |
216 | return(dtsap_sel); | |
217 | } | |
218 | ||
219 | /*------------------------------------------------------------------*/ | |
220 | /* | |
221 | * Function irnet_find_lsap_sel (self) | |
222 | * | |
223 | * Try to lookup LSAP selector in remote LM-IAS | |
224 | * | |
225 | * Basically, we start a IAP query, and then go to sleep. When the query | |
226 | * return, irnet_getvalue_confirm will wake us up, and we can examine the | |
227 | * result of the query... | |
228 | * Note that in some case, the query fail even before we go to sleep, | |
229 | * creating some races... | |
230 | */ | |
231 | static inline int | |
232 | irnet_find_lsap_sel(irnet_socket * self) | |
233 | { | |
234 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | |
235 | ||
236 | /* This should not happen */ | |
237 | DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n"); | |
238 | ||
239 | /* Create an IAP instance, will be closed in irnet_getvalue_confirm() */ | |
240 | self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, | |
241 | irnet_getvalue_confirm); | |
242 | ||
243 | /* Treat unexpected signals as disconnect */ | |
244 | self->errno = -EHOSTUNREACH; | |
245 | ||
246 | /* Query remote LM-IAS */ | |
247 | iriap_getvaluebyclass_request(self->iriap, self->rsaddr, self->daddr, | |
248 | IRNET_SERVICE_NAME, IRNET_IAS_VALUE); | |
249 | ||
250 | /* The above request is non-blocking. | |
251 | * After a while, IrDA will call us back in irnet_getvalue_confirm() | |
252 | * We will then call irnet_ias_to_tsap() and finish the | |
253 | * connection procedure */ | |
254 | ||
255 | DEXIT(IRDA_SR_TRACE, "\n"); | |
256 | return 0; | |
257 | } | |
258 | ||
259 | /*------------------------------------------------------------------*/ | |
260 | /* | |
261 | * Function irnet_connect_tsap (self) | |
262 | * | |
263 | * Initialise the TTP socket and initiate TTP connection | |
264 | * | |
265 | */ | |
266 | static inline int | |
267 | irnet_connect_tsap(irnet_socket * self) | |
268 | { | |
269 | int err; | |
270 | ||
271 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | |
272 | ||
273 | /* Open a local TSAP (an IrTTP instance) */ | |
274 | err = irnet_open_tsap(self); | |
275 | if(err != 0) | |
276 | { | |
277 | clear_bit(0, &self->ttp_connect); | |
278 | DERROR(IRDA_SR_ERROR, "connect aborted!\n"); | |
279 | return(err); | |
280 | } | |
281 | ||
282 | /* Connect to remote device */ | |
283 | err = irttp_connect_request(self->tsap, self->dtsap_sel, | |
284 | self->rsaddr, self->daddr, NULL, | |
285 | self->max_sdu_size_rx, NULL); | |
286 | if(err != 0) | |
287 | { | |
288 | clear_bit(0, &self->ttp_connect); | |
289 | DERROR(IRDA_SR_ERROR, "connect aborted!\n"); | |
290 | return(err); | |
291 | } | |
292 | ||
293 | /* The above call is non-blocking. | |
294 | * After a while, the IrDA stack will either call us back in | |
295 | * irnet_connect_confirm() or irnet_disconnect_indication() | |
296 | * See you there ;-) */ | |
297 | ||
298 | DEXIT(IRDA_SR_TRACE, "\n"); | |
299 | return(err); | |
300 | } | |
301 | ||
302 | /*------------------------------------------------------------------*/ | |
303 | /* | |
304 | * Function irnet_discover_next_daddr (self) | |
305 | * | |
306 | * Query the IrNET TSAP of the next device in the log. | |
307 | * | |
308 | * Used in the TSAP discovery procedure. | |
309 | */ | |
310 | static inline int | |
311 | irnet_discover_next_daddr(irnet_socket * self) | |
312 | { | |
313 | /* Close the last instance of IrIAP, and open a new one. | |
314 | * We can't reuse the IrIAP instance in the IrIAP callback */ | |
315 | if(self->iriap) | |
316 | { | |
317 | iriap_close(self->iriap); | |
318 | self->iriap = NULL; | |
319 | } | |
320 | /* Create a new IAP instance */ | |
321 | self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, | |
322 | irnet_discovervalue_confirm); | |
323 | if(self->iriap == NULL) | |
324 | return -ENOMEM; | |
325 | ||
326 | /* Next discovery - before the call to avoid races */ | |
327 | self->disco_index++; | |
328 | ||
329 | /* Check if we have one more address to try */ | |
330 | if(self->disco_index < self->disco_number) | |
331 | { | |
332 | /* Query remote LM-IAS */ | |
333 | iriap_getvaluebyclass_request(self->iriap, | |
334 | self->discoveries[self->disco_index].saddr, | |
335 | self->discoveries[self->disco_index].daddr, | |
336 | IRNET_SERVICE_NAME, IRNET_IAS_VALUE); | |
337 | /* The above request is non-blocking. | |
338 | * After a while, IrDA will call us back in irnet_discovervalue_confirm() | |
339 | * We will then call irnet_ias_to_tsap() and come back here again... */ | |
340 | return(0); | |
341 | } | |
342 | else | |
343 | return(1); | |
344 | } | |
345 | ||
346 | /*------------------------------------------------------------------*/ | |
347 | /* | |
348 | * Function irnet_discover_daddr_and_lsap_sel (self) | |
349 | * | |
350 | * This try to find a device with the requested service. | |
351 | * | |
352 | * Initiate a TSAP discovery procedure. | |
353 | * It basically look into the discovery log. For each address in the list, | |
354 | * it queries the LM-IAS of the device to find if this device offer | |
355 | * the requested service. | |
356 | * If there is more than one node supporting the service, we complain | |
357 | * to the user (it should move devices around). | |
358 | * If we find one node which have the requested TSAP, we connect to it. | |
359 | * | |
360 | * This function just start the whole procedure. It request the discovery | |
361 | * log and submit the first IAS query. | |
362 | * The bulk of the job is handled in irnet_discovervalue_confirm() | |
363 | * | |
364 | * Note : this procedure fails if there is more than one device in range | |
365 | * on the same dongle, because IrLMP doesn't disconnect the LAP when the | |
366 | * last LSAP is closed. Moreover, we would need to wait the LAP | |
367 | * disconnection... | |
368 | */ | |
369 | static inline int | |
370 | irnet_discover_daddr_and_lsap_sel(irnet_socket * self) | |
371 | { | |
372 | int ret; | |
373 | ||
374 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | |
375 | ||
376 | /* Ask lmp for the current discovery log */ | |
377 | self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask, | |
378 | DISCOVERY_DEFAULT_SLOTS); | |
379 | ||
380 | /* Check if the we got some results */ | |
381 | if(self->discoveries == NULL) | |
382 | { | |
383 | self->disco_number = -1; | |
384 | clear_bit(0, &self->ttp_connect); | |
385 | DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n"); | |
386 | } | |
387 | DEBUG(IRDA_SR_INFO, "Got the log (0x%p), size is %d\n", | |
388 | self->discoveries, self->disco_number); | |
389 | ||
390 | /* Start with the first discovery */ | |
391 | self->disco_index = -1; | |
392 | self->daddr = DEV_ADDR_ANY; | |
393 | ||
394 | /* This will fail if the log is empty - this is non-blocking */ | |
395 | ret = irnet_discover_next_daddr(self); | |
396 | if(ret) | |
397 | { | |
398 | /* Close IAP */ | |
399 | if(self->iriap) | |
400 | iriap_close(self->iriap); | |
401 | self->iriap = NULL; | |
402 | ||
403 | /* Cleanup our copy of the discovery log */ | |
404 | kfree(self->discoveries); | |
405 | self->discoveries = NULL; | |
406 | ||
407 | clear_bit(0, &self->ttp_connect); | |
408 | DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); | |
409 | } | |
410 | ||
411 | /* Follow me in irnet_discovervalue_confirm() */ | |
412 | ||
413 | DEXIT(IRDA_SR_TRACE, "\n"); | |
414 | return(0); | |
415 | } | |
416 | ||
417 | /*------------------------------------------------------------------*/ | |
418 | /* | |
419 | * Function irnet_dname_to_daddr (self) | |
420 | * | |
421 | * Convert an IrDA nickname to a valid IrDA address | |
422 | * | |
423 | * It basically look into the discovery log until there is a match. | |
424 | */ | |
425 | static inline int | |
426 | irnet_dname_to_daddr(irnet_socket * self) | |
427 | { | |
428 | struct irda_device_info *discoveries; /* Copy of the discovery log */ | |
429 | int number; /* Number of nodes in the log */ | |
430 | int i; | |
431 | ||
432 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | |
433 | ||
434 | /* Ask lmp for the current discovery log */ | |
435 | discoveries = irlmp_get_discoveries(&number, 0xffff, | |
436 | DISCOVERY_DEFAULT_SLOTS); | |
437 | /* Check if the we got some results */ | |
438 | if(discoveries == NULL) | |
439 | DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); | |
440 | ||
441 | /* | |
442 | * Now, check all discovered devices (if any), and connect | |
443 | * client only about the services that the client is | |
444 | * interested in... | |
445 | */ | |
446 | for(i = 0; i < number; i++) | |
447 | { | |
448 | /* Does the name match ? */ | |
449 | if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN)) | |
450 | { | |
451 | /* Yes !!! Get it.. */ | |
452 | self->daddr = discoveries[i].daddr; | |
453 | DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n", | |
454 | self->rname, self->daddr); | |
455 | kfree(discoveries); | |
456 | DEXIT(IRDA_SR_TRACE, "\n"); | |
457 | return 0; | |
458 | } | |
459 | } | |
460 | /* No luck ! */ | |
461 | DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname); | |
462 | kfree(discoveries); | |
463 | return(-EADDRNOTAVAIL); | |
464 | } | |
465 | ||
466 | ||
467 | /************************* SOCKET ROUTINES *************************/ | |
468 | /* | |
469 | * This are the main operations on IrNET sockets, basically to create | |
470 | * and destroy IrNET sockets. These are called from the PPP part... | |
471 | */ | |
472 | ||
473 | /*------------------------------------------------------------------*/ | |
474 | /* | |
475 | * Create a IrNET instance : just initialise some parameters... | |
476 | */ | |
477 | int | |
478 | irda_irnet_create(irnet_socket * self) | |
479 | { | |
480 | DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); | |
481 | ||
482 | self->magic = IRNET_MAGIC; /* Paranoia */ | |
483 | ||
484 | self->ttp_open = 0; /* Prevent higher layer from accessing IrTTP */ | |
485 | self->ttp_connect = 0; /* Not connecting yet */ | |
486 | self->rname[0] = '\0'; /* May be set via control channel */ | |
487 | self->rdaddr = DEV_ADDR_ANY; /* May be set via control channel */ | |
488 | self->rsaddr = DEV_ADDR_ANY; /* May be set via control channel */ | |
489 | self->daddr = DEV_ADDR_ANY; /* Until we get connected */ | |
490 | self->saddr = DEV_ADDR_ANY; /* Until we get connected */ | |
491 | self->max_sdu_size_rx = TTP_SAR_UNBOUND; | |
492 | ||
493 | /* Register as a client with IrLMP */ | |
494 | self->ckey = irlmp_register_client(0, NULL, NULL, NULL); | |
495 | #ifdef DISCOVERY_NOMASK | |
496 | self->mask = 0xffff; /* For W2k compatibility */ | |
497 | #else /* DISCOVERY_NOMASK */ | |
498 | self->mask = irlmp_service_to_hint(S_LAN); | |
499 | #endif /* DISCOVERY_NOMASK */ | |
500 | self->tx_flow = FLOW_START; /* Flow control from IrTTP */ | |
501 | ||
502 | DEXIT(IRDA_SOCK_TRACE, "\n"); | |
503 | return(0); | |
504 | } | |
505 | ||
506 | /*------------------------------------------------------------------*/ | |
507 | /* | |
508 | * Connect to the other side : | |
509 | * o convert device name to an address | |
510 | * o find the socket number (dlsap) | |
511 | * o Establish the connection | |
512 | * | |
513 | * Note : We no longer mimic af_irda. The IAS query for finding the TSAP | |
514 | * is done asynchronously, like the TTP connection. This allow us to | |
515 | * call this function from any context (not only process). | |
516 | * The downside is that following what's happening in there is tricky | |
517 | * because it involve various functions all over the place... | |
518 | */ | |
519 | int | |
520 | irda_irnet_connect(irnet_socket * self) | |
521 | { | |
522 | int err; | |
523 | ||
524 | DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); | |
525 | ||
526 | /* Check if we are already trying to connect. | |
527 | * Because irda_irnet_connect() can be called directly by pppd plus | |
528 | * packet retries in ppp_generic and connect may take time, plus we may | |
529 | * race with irnet_connect_indication(), we need to be careful there... */ | |
530 | if(test_and_set_bit(0, &self->ttp_connect)) | |
531 | DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n"); | |
532 | if((self->iriap != NULL) || (self->tsap != NULL)) | |
533 | DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n"); | |
534 | ||
535 | /* Insert ourselves in the hashbin so that the IrNET server can find us. | |
536 | * Notes : 4th arg is string of 32 char max and must be null terminated | |
537 | * When 4th arg is used (string), 3rd arg isn't (int) | |
538 | * Can't re-insert (MUST remove first) so check for that... */ | |
539 | if((irnet_server.running) && (self->q.q_next == NULL)) | |
540 | { | |
541 | spin_lock_bh(&irnet_server.spinlock); | |
542 | hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname); | |
543 | spin_unlock_bh(&irnet_server.spinlock); | |
544 | DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname); | |
545 | } | |
546 | ||
547 | /* If we don't have anything (no address, no name) */ | |
548 | if((self->rdaddr == DEV_ADDR_ANY) && (self->rname[0] == '\0')) | |
549 | { | |
550 | /* Try to find a suitable address */ | |
551 | if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0) | |
552 | DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n"); | |
553 | /* In most cases, the call above is non-blocking */ | |
554 | } | |
555 | else | |
556 | { | |
557 | /* If we have only the name (no address), try to get an address */ | |
558 | if(self->rdaddr == DEV_ADDR_ANY) | |
559 | { | |
560 | if((err = irnet_dname_to_daddr(self)) != 0) | |
561 | DRETURN(err, IRDA_SOCK_INFO, "name connect failed!\n"); | |
562 | } | |
563 | else | |
564 | /* Use the requested destination address */ | |
565 | self->daddr = self->rdaddr; | |
566 | ||
567 | /* Query remote LM-IAS to find LSAP selector */ | |
568 | irnet_find_lsap_sel(self); | |
569 | /* The above call is non blocking */ | |
570 | } | |
571 | ||
572 | /* At this point, we are waiting for the IrDA stack to call us back, | |
573 | * or we have already failed. | |
574 | * We will finish the connection procedure in irnet_connect_tsap(). | |
575 | */ | |
576 | DEXIT(IRDA_SOCK_TRACE, "\n"); | |
577 | return(0); | |
578 | } | |
579 | ||
580 | /*------------------------------------------------------------------*/ | |
581 | /* | |
582 | * Function irda_irnet_destroy(self) | |
583 | * | |
584 | * Destroy irnet instance | |
585 | * | |
586 | * Note : this need to be called from a process context. | |
587 | */ | |
588 | void | |
589 | irda_irnet_destroy(irnet_socket * self) | |
590 | { | |
591 | DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); | |
592 | if(self == NULL) | |
593 | return; | |
594 | ||
595 | /* Remove ourselves from hashbin (if we are queued in hashbin) | |
596 | * Note : `irnet_server.running' protect us from calls in hashbin_delete() */ | |
597 | if((irnet_server.running) && (self->q.q_next != NULL)) | |
598 | { | |
599 | struct irnet_socket * entry; | |
600 | DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n"); | |
601 | spin_lock_bh(&irnet_server.spinlock); | |
602 | entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self); | |
603 | self->q.q_next = NULL; | |
604 | spin_unlock_bh(&irnet_server.spinlock); | |
605 | DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n"); | |
606 | } | |
607 | ||
608 | /* If we were connected, post a message */ | |
609 | if(test_bit(0, &self->ttp_open)) | |
610 | { | |
611 | /* Note : as the disconnect comes from ppp_generic, the unit number | |
612 | * doesn't exist anymore when we post the event, so we need to pass | |
613 | * NULL as the first arg... */ | |
614 | irnet_post_event(NULL, IRNET_DISCONNECT_TO, | |
615 | self->saddr, self->daddr, self->rname, 0); | |
616 | } | |
617 | ||
618 | /* Prevent various IrDA callbacks from messing up things | |
619 | * Need to be first */ | |
620 | clear_bit(0, &self->ttp_connect); | |
621 | ||
622 | /* Prevent higher layer from accessing IrTTP */ | |
623 | clear_bit(0, &self->ttp_open); | |
624 | ||
625 | /* Unregister with IrLMP */ | |
626 | irlmp_unregister_client(self->ckey); | |
627 | ||
628 | /* Unregister with LM-IAS */ | |
629 | if(self->iriap) | |
630 | { | |
631 | iriap_close(self->iriap); | |
632 | self->iriap = NULL; | |
633 | } | |
634 | ||
635 | /* Cleanup eventual discoveries from connection attempt or control channel */ | |
636 | if(self->discoveries != NULL) | |
637 | { | |
638 | /* Cleanup our copy of the discovery log */ | |
639 | kfree(self->discoveries); | |
640 | self->discoveries = NULL; | |
641 | } | |
642 | ||
643 | /* Close our IrTTP connection */ | |
644 | if(self->tsap) | |
645 | { | |
646 | DEBUG(IRDA_SOCK_INFO, "Closing our TTP connection.\n"); | |
647 | irttp_disconnect_request(self->tsap, NULL, P_NORMAL); | |
648 | irttp_close_tsap(self->tsap); | |
649 | self->tsap = NULL; | |
650 | } | |
651 | self->stsap_sel = 0; | |
652 | ||
653 | DEXIT(IRDA_SOCK_TRACE, "\n"); | |
654 | return; | |
655 | } | |
656 | ||
657 | ||
658 | /************************** SERVER SOCKET **************************/ | |
659 | /* | |
660 | * The IrNET service is composed of one server socket and a variable | |
661 | * number of regular IrNET sockets. The server socket is supposed to | |
662 | * handle incoming connections and redirect them to one IrNET sockets. | |
663 | * It's a superset of the regular IrNET socket, but has a very distinct | |
664 | * behaviour... | |
665 | */ | |
666 | ||
667 | /*------------------------------------------------------------------*/ | |
668 | /* | |
669 | * Function irnet_daddr_to_dname (self) | |
670 | * | |
671 | * Convert an IrDA address to a IrDA nickname | |
672 | * | |
673 | * It basically look into the discovery log until there is a match. | |
674 | */ | |
675 | static inline int | |
676 | irnet_daddr_to_dname(irnet_socket * self) | |
677 | { | |
678 | struct irda_device_info *discoveries; /* Copy of the discovery log */ | |
679 | int number; /* Number of nodes in the log */ | |
680 | int i; | |
681 | ||
682 | DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); | |
683 | ||
684 | /* Ask lmp for the current discovery log */ | |
685 | discoveries = irlmp_get_discoveries(&number, 0xffff, | |
686 | DISCOVERY_DEFAULT_SLOTS); | |
687 | /* Check if the we got some results */ | |
688 | if (discoveries == NULL) | |
689 | DRETURN(-ENETUNREACH, IRDA_SERV_INFO, "Cachelog empty...\n"); | |
690 | ||
691 | /* Now, check all discovered devices (if any) */ | |
692 | for(i = 0; i < number; i++) | |
693 | { | |
694 | /* Does the name match ? */ | |
695 | if(discoveries[i].daddr == self->daddr) | |
696 | { | |
697 | /* Yes !!! Get it.. */ | |
698 | strlcpy(self->rname, discoveries[i].info, sizeof(self->rname)); | |
80ba250e | 699 | self->rname[sizeof(self->rname) - 1] = '\0'; |
1da177e4 LT |
700 | DEBUG(IRDA_SERV_INFO, "Device 0x%08x is in fact ``%s''.\n", |
701 | self->daddr, self->rname); | |
702 | kfree(discoveries); | |
703 | DEXIT(IRDA_SERV_TRACE, "\n"); | |
704 | return 0; | |
705 | } | |
706 | } | |
707 | /* No luck ! */ | |
708 | DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr); | |
709 | kfree(discoveries); | |
710 | return(-EADDRNOTAVAIL); | |
711 | } | |
712 | ||
713 | /*------------------------------------------------------------------*/ | |
714 | /* | |
715 | * Function irda_find_socket (self) | |
716 | * | |
717 | * Find the correct IrNET socket | |
718 | * | |
719 | * Look into the list of IrNET sockets and finds one with the right | |
720 | * properties... | |
721 | */ | |
722 | static inline irnet_socket * | |
723 | irnet_find_socket(irnet_socket * self) | |
724 | { | |
725 | irnet_socket * new = (irnet_socket *) NULL; | |
726 | int err; | |
727 | ||
728 | DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); | |
729 | ||
730 | /* Get the addresses of the requester */ | |
731 | self->daddr = irttp_get_daddr(self->tsap); | |
732 | self->saddr = irttp_get_saddr(self->tsap); | |
733 | ||
734 | /* Try to get the IrDA nickname of the requester */ | |
735 | err = irnet_daddr_to_dname(self); | |
736 | ||
737 | /* Protect access to the instance list */ | |
738 | spin_lock_bh(&irnet_server.spinlock); | |
739 | ||
740 | /* So now, try to get an socket having specifically | |
741 | * requested that nickname */ | |
742 | if(err == 0) | |
743 | { | |
744 | new = (irnet_socket *) hashbin_find(irnet_server.list, | |
745 | 0, self->rname); | |
746 | if(new) | |
747 | DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches rname ``%s''.\n", | |
748 | new, new->rname); | |
749 | } | |
750 | ||
751 | /* If no name matches, try to find an socket by the destination address */ | |
752 | /* It can be either the requested destination address (set via the | |
753 | * control channel), or the current destination address if the | |
754 | * socket is in the middle of a connection request */ | |
755 | if(new == (irnet_socket *) NULL) | |
756 | { | |
757 | new = (irnet_socket *) hashbin_get_first(irnet_server.list); | |
758 | while(new !=(irnet_socket *) NULL) | |
759 | { | |
760 | /* Does it have the same address ? */ | |
761 | if((new->rdaddr == self->daddr) || (new->daddr == self->daddr)) | |
762 | { | |
763 | /* Yes !!! Get it.. */ | |
764 | DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches daddr %#08x.\n", | |
765 | new, self->daddr); | |
766 | break; | |
767 | } | |
768 | new = (irnet_socket *) hashbin_get_next(irnet_server.list); | |
769 | } | |
770 | } | |
771 | ||
772 | /* If we don't have any socket, get the first unconnected socket */ | |
773 | if(new == (irnet_socket *) NULL) | |
774 | { | |
775 | new = (irnet_socket *) hashbin_get_first(irnet_server.list); | |
776 | while(new !=(irnet_socket *) NULL) | |
777 | { | |
778 | /* Is it available ? */ | |
779 | if(!(test_bit(0, &new->ttp_open)) && (new->rdaddr == DEV_ADDR_ANY) && | |
780 | (new->rname[0] == '\0') && (new->ppp_open)) | |
781 | { | |
782 | /* Yes !!! Get it.. */ | |
783 | DEBUG(IRDA_SERV_INFO, "Socket 0x%p is free.\n", | |
784 | new); | |
785 | break; | |
786 | } | |
787 | new = (irnet_socket *) hashbin_get_next(irnet_server.list); | |
788 | } | |
789 | } | |
790 | ||
791 | /* Spin lock end */ | |
792 | spin_unlock_bh(&irnet_server.spinlock); | |
793 | ||
794 | DEXIT(IRDA_SERV_TRACE, " - new = 0x%p\n", new); | |
795 | return new; | |
796 | } | |
797 | ||
798 | /*------------------------------------------------------------------*/ | |
799 | /* | |
800 | * Function irda_connect_socket (self) | |
801 | * | |
802 | * Connect an incoming connection to the socket | |
803 | * | |
804 | */ | |
805 | static inline int | |
806 | irnet_connect_socket(irnet_socket * server, | |
807 | irnet_socket * new, | |
808 | struct qos_info * qos, | |
809 | __u32 max_sdu_size, | |
810 | __u8 max_header_size) | |
811 | { | |
812 | DENTER(IRDA_SERV_TRACE, "(server=0x%p, new=0x%p)\n", | |
813 | server, new); | |
814 | ||
815 | /* Now attach up the new socket */ | |
816 | new->tsap = irttp_dup(server->tsap, new); | |
817 | DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n"); | |
818 | ||
819 | /* Set up all the relevant parameters on the new socket */ | |
820 | new->stsap_sel = new->tsap->stsap_sel; | |
821 | new->dtsap_sel = new->tsap->dtsap_sel; | |
822 | new->saddr = irttp_get_saddr(new->tsap); | |
823 | new->daddr = irttp_get_daddr(new->tsap); | |
824 | ||
825 | new->max_header_size = max_header_size; | |
826 | new->max_sdu_size_tx = max_sdu_size; | |
827 | new->max_data_size = max_sdu_size; | |
828 | #ifdef STREAM_COMPAT | |
829 | /* If we want to receive "stream sockets" */ | |
830 | if(max_sdu_size == 0) | |
831 | new->max_data_size = irttp_get_max_seg_size(new->tsap); | |
832 | #endif /* STREAM_COMPAT */ | |
833 | ||
834 | /* Clean up the original one to keep it in listen state */ | |
835 | irttp_listen(server->tsap); | |
836 | ||
837 | /* Send a connection response on the new socket */ | |
838 | irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL); | |
839 | ||
840 | /* Allow PPP to send its junk over the new socket... */ | |
841 | set_bit(0, &new->ttp_open); | |
842 | ||
843 | /* Not connecting anymore, and clean up last possible remains | |
844 | * of connection attempts on the socket */ | |
845 | clear_bit(0, &new->ttp_connect); | |
846 | if(new->iriap) | |
847 | { | |
848 | iriap_close(new->iriap); | |
849 | new->iriap = NULL; | |
850 | } | |
851 | if(new->discoveries != NULL) | |
852 | { | |
853 | kfree(new->discoveries); | |
854 | new->discoveries = NULL; | |
855 | } | |
856 | ||
857 | #ifdef CONNECT_INDIC_KICK | |
858 | /* As currently we don't block packets in ppp_irnet_send() while passive, | |
859 | * this is not really needed... | |
860 | * Also, not doing it give IrDA a chance to finish the setup properly | |
861 | * before being swamped with packets... */ | |
862 | ppp_output_wakeup(&new->chan); | |
863 | #endif /* CONNECT_INDIC_KICK */ | |
864 | ||
865 | /* Notify the control channel */ | |
866 | irnet_post_event(new, IRNET_CONNECT_FROM, | |
867 | new->saddr, new->daddr, server->rname, 0); | |
868 | ||
869 | DEXIT(IRDA_SERV_TRACE, "\n"); | |
870 | return 0; | |
871 | } | |
872 | ||
873 | /*------------------------------------------------------------------*/ | |
874 | /* | |
875 | * Function irda_disconnect_server (self) | |
876 | * | |
877 | * Cleanup the server socket when the incoming connection abort | |
878 | * | |
879 | */ | |
880 | static inline void | |
881 | irnet_disconnect_server(irnet_socket * self, | |
882 | struct sk_buff *skb) | |
883 | { | |
884 | DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); | |
885 | ||
886 | /* Put the received packet in the black hole */ | |
887 | kfree_skb(skb); | |
888 | ||
889 | #ifdef FAIL_SEND_DISCONNECT | |
890 | /* Tell the other party we don't want to be connected */ | |
891 | /* Hum... Is it the right thing to do ? And do we need to send | |
892 | * a connect response before ? It looks ok without this... */ | |
893 | irttp_disconnect_request(self->tsap, NULL, P_NORMAL); | |
894 | #endif /* FAIL_SEND_DISCONNECT */ | |
895 | ||
896 | /* Notify the control channel (see irnet_find_socket()) */ | |
897 | irnet_post_event(NULL, IRNET_REQUEST_FROM, | |
898 | self->saddr, self->daddr, self->rname, 0); | |
899 | ||
900 | /* Clean up the server to keep it in listen state */ | |
901 | irttp_listen(self->tsap); | |
902 | ||
903 | DEXIT(IRDA_SERV_TRACE, "\n"); | |
904 | return; | |
905 | } | |
906 | ||
907 | /*------------------------------------------------------------------*/ | |
908 | /* | |
909 | * Function irda_setup_server (self) | |
910 | * | |
911 | * Create a IrTTP server and set it up... | |
912 | * | |
913 | * Register the IrLAN hint bit, create a IrTTP instance for us, | |
914 | * set all the IrTTP callbacks and create an IrIAS entry... | |
915 | */ | |
916 | static inline int | |
917 | irnet_setup_server(void) | |
918 | { | |
919 | __u16 hints; | |
920 | ||
921 | DENTER(IRDA_SERV_TRACE, "()\n"); | |
922 | ||
923 | /* Initialise the regular socket part of the server */ | |
924 | irda_irnet_create(&irnet_server.s); | |
925 | ||
926 | /* Open a local TSAP (an IrTTP instance) for the server */ | |
927 | irnet_open_tsap(&irnet_server.s); | |
928 | ||
929 | /* PPP part setup */ | |
930 | irnet_server.s.ppp_open = 0; | |
931 | irnet_server.s.chan.private = NULL; | |
932 | irnet_server.s.file = NULL; | |
933 | ||
934 | /* Get the hint bit corresponding to IrLAN */ | |
935 | /* Note : we overload the IrLAN hint bit. As it is only a "hint", and as | |
936 | * we provide roughly the same functionality as IrLAN, this is ok. | |
937 | * In fact, the situation is similar as JetSend overloading the Obex hint | |
938 | */ | |
939 | hints = irlmp_service_to_hint(S_LAN); | |
940 | ||
941 | #ifdef ADVERTISE_HINT | |
942 | /* Register with IrLMP as a service (advertise our hint bit) */ | |
943 | irnet_server.skey = irlmp_register_service(hints); | |
944 | #endif /* ADVERTISE_HINT */ | |
945 | ||
946 | /* Register with LM-IAS (so that people can connect to us) */ | |
947 | irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies); | |
948 | irias_add_integer_attrib(irnet_server.ias_obj, IRNET_IAS_VALUE, | |
949 | irnet_server.s.stsap_sel, IAS_KERNEL_ATTR); | |
950 | irias_insert_object(irnet_server.ias_obj); | |
951 | ||
952 | #ifdef DISCOVERY_EVENTS | |
953 | /* Tell IrLMP we want to be notified of newly discovered nodes */ | |
954 | irlmp_update_client(irnet_server.s.ckey, hints, | |
955 | irnet_discovery_indication, irnet_expiry_indication, | |
956 | (void *) &irnet_server.s); | |
957 | #endif | |
958 | ||
959 | DEXIT(IRDA_SERV_TRACE, " - self=0x%p\n", &irnet_server.s); | |
960 | return 0; | |
961 | } | |
962 | ||
963 | /*------------------------------------------------------------------*/ | |
964 | /* | |
965 | * Function irda_destroy_server (self) | |
966 | * | |
967 | * Destroy the IrTTP server... | |
968 | * | |
969 | * Reverse of the previous function... | |
970 | */ | |
971 | static inline void | |
972 | irnet_destroy_server(void) | |
973 | { | |
974 | DENTER(IRDA_SERV_TRACE, "()\n"); | |
975 | ||
976 | #ifdef ADVERTISE_HINT | |
977 | /* Unregister with IrLMP */ | |
978 | irlmp_unregister_service(irnet_server.skey); | |
979 | #endif /* ADVERTISE_HINT */ | |
980 | ||
981 | /* Unregister with LM-IAS */ | |
982 | if(irnet_server.ias_obj) | |
983 | irias_delete_object(irnet_server.ias_obj); | |
984 | ||
985 | /* Cleanup the socket part */ | |
986 | irda_irnet_destroy(&irnet_server.s); | |
987 | ||
988 | DEXIT(IRDA_SERV_TRACE, "\n"); | |
989 | return; | |
990 | } | |
991 | ||
992 | ||
993 | /************************ IRDA-TTP CALLBACKS ************************/ | |
994 | /* | |
995 | * When we create a IrTTP instance, we pass to it a set of callbacks | |
996 | * that IrTTP will call in case of various events. | |
997 | * We take care of those events here. | |
998 | */ | |
999 | ||
1000 | /*------------------------------------------------------------------*/ | |
1001 | /* | |
1002 | * Function irnet_data_indication (instance, sap, skb) | |
1003 | * | |
1004 | * Received some data from TinyTP. Just queue it on the receive queue | |
1005 | * | |
1006 | */ | |
1007 | static int | |
1008 | irnet_data_indication(void * instance, | |
1009 | void * sap, | |
1010 | struct sk_buff *skb) | |
1011 | { | |
1012 | irnet_socket * ap = (irnet_socket *) instance; | |
1013 | unsigned char * p; | |
1014 | int code = 0; | |
1015 | ||
1016 | DENTER(IRDA_TCB_TRACE, "(self/ap=0x%p, skb=0x%p)\n", | |
1017 | ap, skb); | |
1018 | DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n"); | |
1019 | ||
1020 | /* Check is ppp is ready to receive our packet */ | |
1021 | if(!ap->ppp_open) | |
1022 | { | |
1023 | DERROR(IRDA_CB_ERROR, "PPP not ready, dropping packet...\n"); | |
1024 | /* When we return error, TTP will need to requeue the skb and | |
1025 | * will stop the sender. IrTTP will stall until we send it a | |
1026 | * flow control request... */ | |
1027 | return -ENOMEM; | |
1028 | } | |
1029 | ||
1030 | /* strip address/control field if present */ | |
1031 | p = skb->data; | |
1032 | if((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI)) | |
1033 | { | |
1034 | /* chop off address/control */ | |
1035 | if(skb->len < 3) | |
1036 | goto err_exit; | |
1037 | p = skb_pull(skb, 2); | |
1038 | } | |
1039 | ||
1040 | /* decompress protocol field if compressed */ | |
1041 | if(p[0] & 1) | |
1042 | { | |
1043 | /* protocol is compressed */ | |
1044 | skb_push(skb, 1)[0] = 0; | |
1045 | } | |
1046 | else | |
1047 | if(skb->len < 2) | |
1048 | goto err_exit; | |
1049 | ||
1050 | /* pass to generic ppp layer */ | |
1051 | /* Note : how do I know if ppp can accept or not the packet ? This is | |
1052 | * essential if I want to manage flow control smoothly... */ | |
1053 | ppp_input(&ap->chan, skb); | |
1054 | ||
1055 | DEXIT(IRDA_TCB_TRACE, "\n"); | |
1056 | return 0; | |
1057 | ||
1058 | err_exit: | |
1059 | DERROR(IRDA_CB_ERROR, "Packet too small, dropping...\n"); | |
1060 | kfree_skb(skb); | |
1061 | ppp_input_error(&ap->chan, code); | |
1062 | return 0; /* Don't return an error code, only for flow control... */ | |
1063 | } | |
1064 | ||
1065 | /*------------------------------------------------------------------*/ | |
1066 | /* | |
1067 | * Function irnet_disconnect_indication (instance, sap, reason, skb) | |
1068 | * | |
1069 | * Connection has been closed. Chech reason to find out why | |
1070 | * | |
1071 | * Note : there are many cases where we come here : | |
1072 | * o attempted to connect, timeout | |
1073 | * o connected, link is broken, LAP has timeout | |
1074 | * o connected, other side close the link | |
1075 | * o connection request on the server not handled | |
1076 | */ | |
1077 | static void | |
1078 | irnet_disconnect_indication(void * instance, | |
1079 | void * sap, | |
1080 | LM_REASON reason, | |
1081 | struct sk_buff *skb) | |
1082 | { | |
1083 | irnet_socket * self = (irnet_socket *) instance; | |
1084 | int test_open; | |
1085 | int test_connect; | |
1086 | ||
1087 | DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); | |
1088 | DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); | |
1089 | ||
1090 | /* Don't care about it, but let's not leak it */ | |
1091 | if(skb) | |
1092 | dev_kfree_skb(skb); | |
1093 | ||
1094 | /* Prevent higher layer from accessing IrTTP */ | |
1095 | test_open = test_and_clear_bit(0, &self->ttp_open); | |
1096 | /* Not connecting anymore... | |
1097 | * (note : TSAP is open, so IAP callbacks are no longer pending...) */ | |
1098 | test_connect = test_and_clear_bit(0, &self->ttp_connect); | |
1099 | ||
1100 | /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we | |
1101 | * have a race condition with irda_irnet_destroy() or | |
1102 | * irnet_connect_indication(), so don't mess up tsap... | |
1103 | */ | |
1104 | if(!(test_open || test_connect)) | |
1105 | { | |
1106 | DERROR(IRDA_CB_ERROR, "Race condition detected...\n"); | |
1107 | return; | |
1108 | } | |
1109 | ||
1110 | /* If we were active, notify the control channel */ | |
1111 | if(test_open) | |
1112 | irnet_post_event(self, IRNET_DISCONNECT_FROM, | |
1113 | self->saddr, self->daddr, self->rname, 0); | |
1114 | else | |
1115 | /* If we were trying to connect, notify the control channel */ | |
1116 | if((self->tsap) && (self != &irnet_server.s)) | |
1117 | irnet_post_event(self, IRNET_NOANSWER_FROM, | |
1118 | self->saddr, self->daddr, self->rname, 0); | |
1119 | ||
1120 | /* Close our IrTTP connection, cleanup tsap */ | |
1121 | if((self->tsap) && (self != &irnet_server.s)) | |
1122 | { | |
1123 | DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n"); | |
1124 | irttp_close_tsap(self->tsap); | |
1125 | self->tsap = NULL; | |
1126 | } | |
1127 | /* Cleanup the socket in case we want to reconnect in ppp_output_wakeup() */ | |
1128 | self->stsap_sel = 0; | |
1129 | self->daddr = DEV_ADDR_ANY; | |
1130 | self->tx_flow = FLOW_START; | |
1131 | ||
1132 | /* Deal with the ppp instance if it's still alive */ | |
1133 | if(self->ppp_open) | |
1134 | { | |
1135 | if(test_open) | |
1136 | { | |
1137 | #ifdef MISSING_PPP_API | |
1138 | /* ppp_unregister_channel() wants a user context, which we | |
1139 | * are guaranteed to NOT have here. What are we supposed | |
1140 | * to do here ? Jean II */ | |
1141 | /* If we were connected, cleanup & close the PPP channel, | |
1142 | * which will kill pppd (hangup) and the rest */ | |
1143 | ppp_unregister_channel(&self->chan); | |
1144 | self->ppp_open = 0; | |
1145 | #endif | |
1146 | } | |
1147 | else | |
1148 | { | |
1149 | /* If we were trying to connect, flush (drain) ppp_generic | |
1150 | * Tx queue (most often we have blocked it), which will | |
1151 | * trigger an other attempt to connect. If we are passive, | |
1152 | * this will empty the Tx queue after last try. */ | |
1153 | ppp_output_wakeup(&self->chan); | |
1154 | } | |
1155 | } | |
1156 | ||
1157 | DEXIT(IRDA_TCB_TRACE, "\n"); | |
1158 | } | |
1159 | ||
1160 | /*------------------------------------------------------------------*/ | |
1161 | /* | |
1162 | * Function irnet_connect_confirm (instance, sap, qos, max_sdu_size, skb) | |
1163 | * | |
1164 | * Connections has been confirmed by the remote device | |
1165 | * | |
1166 | */ | |
1167 | static void | |
1168 | irnet_connect_confirm(void * instance, | |
1169 | void * sap, | |
1170 | struct qos_info *qos, | |
1171 | __u32 max_sdu_size, | |
1172 | __u8 max_header_size, | |
1173 | struct sk_buff *skb) | |
1174 | { | |
1175 | irnet_socket * self = (irnet_socket *) instance; | |
1176 | ||
1177 | DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); | |
1178 | ||
1179 | /* Check if socket is closing down (via irda_irnet_destroy()) */ | |
1180 | if(! test_bit(0, &self->ttp_connect)) | |
1181 | { | |
1182 | DERROR(IRDA_CB_ERROR, "Socket no longer connecting. Ouch !\n"); | |
1183 | return; | |
1184 | } | |
1185 | ||
1186 | /* How much header space do we need to reserve */ | |
1187 | self->max_header_size = max_header_size; | |
1188 | ||
1189 | /* IrTTP max SDU size in transmit direction */ | |
1190 | self->max_sdu_size_tx = max_sdu_size; | |
1191 | self->max_data_size = max_sdu_size; | |
1192 | #ifdef STREAM_COMPAT | |
1193 | if(max_sdu_size == 0) | |
1194 | self->max_data_size = irttp_get_max_seg_size(self->tsap); | |
1195 | #endif /* STREAM_COMPAT */ | |
1196 | ||
1197 | /* At this point, IrLMP has assigned our source address */ | |
1198 | self->saddr = irttp_get_saddr(self->tsap); | |
1199 | ||
1200 | /* Allow higher layer to access IrTTP */ | |
1201 | set_bit(0, &self->ttp_open); | |
1202 | clear_bit(0, &self->ttp_connect); /* Not racy, IrDA traffic is serial */ | |
1203 | /* Give a kick in the ass of ppp_generic so that he sends us some data */ | |
1204 | ppp_output_wakeup(&self->chan); | |
1205 | ||
1206 | /* Check size of received packet */ | |
1207 | if(skb->len > 0) | |
1208 | { | |
1209 | #ifdef PASS_CONNECT_PACKETS | |
1210 | DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); | |
1211 | /* Try to pass it to PPP */ | |
1212 | irnet_data_indication(instance, sap, skb); | |
1213 | #else /* PASS_CONNECT_PACKETS */ | |
1214 | DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); | |
1215 | kfree_skb(skb); /* Note : will be optimised with other kfree... */ | |
1216 | #endif /* PASS_CONNECT_PACKETS */ | |
1217 | } | |
1218 | else | |
1219 | kfree_skb(skb); | |
1220 | ||
1221 | /* Notify the control channel */ | |
1222 | irnet_post_event(self, IRNET_CONNECT_TO, | |
1223 | self->saddr, self->daddr, self->rname, 0); | |
1224 | ||
1225 | DEXIT(IRDA_TCB_TRACE, "\n"); | |
1226 | } | |
1227 | ||
1228 | /*------------------------------------------------------------------*/ | |
1229 | /* | |
1230 | * Function irnet_flow_indication (instance, sap, flow) | |
1231 | * | |
1232 | * Used by TinyTP to tell us if it can accept more data or not | |
1233 | * | |
1234 | */ | |
1235 | static void | |
1236 | irnet_flow_indication(void * instance, | |
1237 | void * sap, | |
1238 | LOCAL_FLOW flow) | |
1239 | { | |
1240 | irnet_socket * self = (irnet_socket *) instance; | |
1241 | LOCAL_FLOW oldflow = self->tx_flow; | |
1242 | ||
1243 | DENTER(IRDA_TCB_TRACE, "(self=0x%p, flow=%d)\n", self, flow); | |
1244 | ||
1245 | /* Update our state */ | |
1246 | self->tx_flow = flow; | |
1247 | ||
1248 | /* Check what IrTTP want us to do... */ | |
1249 | switch(flow) | |
1250 | { | |
1251 | case FLOW_START: | |
1252 | DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n"); | |
1253 | /* Check if we really need to wake up PPP */ | |
1254 | if(oldflow == FLOW_STOP) | |
1255 | ppp_output_wakeup(&self->chan); | |
1256 | else | |
1257 | DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n"); | |
1258 | break; | |
1259 | case FLOW_STOP: | |
1260 | DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n"); | |
1261 | break; | |
1262 | default: | |
1263 | DEBUG(IRDA_CB_INFO, "Unknown flow command!\n"); | |
1264 | break; | |
1265 | } | |
1266 | ||
1267 | DEXIT(IRDA_TCB_TRACE, "\n"); | |
1268 | } | |
1269 | ||
1270 | /*------------------------------------------------------------------*/ | |
1271 | /* | |
1272 | * Function irnet_status_indication (instance, sap, reason, skb) | |
1273 | * | |
1274 | * Link (IrLAP) status report. | |
1275 | * | |
1276 | */ | |
1277 | static void | |
1278 | irnet_status_indication(void * instance, | |
1279 | LINK_STATUS link, | |
1280 | LOCK_STATUS lock) | |
1281 | { | |
1282 | irnet_socket * self = (irnet_socket *) instance; | |
1283 | ||
1284 | DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); | |
1285 | DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); | |
1286 | ||
1287 | /* We can only get this event if we are connected */ | |
1288 | switch(link) | |
1289 | { | |
1290 | case STATUS_NO_ACTIVITY: | |
1291 | irnet_post_event(self, IRNET_BLOCKED_LINK, | |
1292 | self->saddr, self->daddr, self->rname, 0); | |
1293 | break; | |
1294 | default: | |
1295 | DEBUG(IRDA_CB_INFO, "Unknown status...\n"); | |
1296 | } | |
1297 | ||
1298 | DEXIT(IRDA_TCB_TRACE, "\n"); | |
1299 | } | |
1300 | ||
1301 | /*------------------------------------------------------------------*/ | |
1302 | /* | |
1303 | * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata) | |
1304 | * | |
1305 | * Incoming connection | |
1306 | * | |
1307 | * In theory, this function is called only on the server socket. | |
1308 | * Some other node is attempting to connect to the IrNET service, and has | |
1309 | * sent a connection request on our server socket. | |
1310 | * We just redirect the connection to the relevant IrNET socket. | |
1311 | * | |
1312 | * Note : we also make sure that between 2 irnet nodes, there can | |
1313 | * exist only one irnet connection. | |
1314 | */ | |
1315 | static void | |
1316 | irnet_connect_indication(void * instance, | |
1317 | void * sap, | |
1318 | struct qos_info *qos, | |
1319 | __u32 max_sdu_size, | |
1320 | __u8 max_header_size, | |
1321 | struct sk_buff *skb) | |
1322 | { | |
1323 | irnet_socket * server = &irnet_server.s; | |
1324 | irnet_socket * new = (irnet_socket *) NULL; | |
1325 | ||
1326 | DENTER(IRDA_TCB_TRACE, "(server=0x%p)\n", server); | |
1327 | DASSERT(instance == &irnet_server, , IRDA_CB_ERROR, | |
1328 | "Invalid instance (0x%p) !!!\n", instance); | |
1329 | DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n"); | |
1330 | ||
1331 | /* Try to find the most appropriate IrNET socket */ | |
1332 | new = irnet_find_socket(server); | |
1333 | ||
1334 | /* After all this hard work, do we have an socket ? */ | |
1335 | if(new == (irnet_socket *) NULL) | |
1336 | { | |
1337 | DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n"); | |
1338 | irnet_disconnect_server(server, skb); | |
1339 | return; | |
1340 | } | |
1341 | ||
1342 | /* Is the socket already busy ? */ | |
1343 | if(test_bit(0, &new->ttp_open)) | |
1344 | { | |
1345 | DEXIT(IRDA_CB_INFO, ": Socket already connected.\n"); | |
1346 | irnet_disconnect_server(server, skb); | |
1347 | return; | |
1348 | } | |
1349 | ||
1350 | /* The following code is a bit tricky, so need comments ;-) | |
1351 | */ | |
1352 | /* If ttp_connect is set, the socket is trying to connect to the other | |
1353 | * end and may have sent a IrTTP connection request and is waiting for | |
1354 | * a connection response (that may never come). | |
1355 | * Now, the pain is that the socket may have opened a tsap and is | |
1356 | * waiting on it, while the other end is trying to connect to it on | |
1357 | * another tsap. | |
1358 | * Because IrNET can be peer to peer, we need to workaround this. | |
1359 | * Furthermore, the way the irnetd script is implemented, the | |
1360 | * target will create a second IrNET connection back to the | |
1361 | * originator and expect the originator to bind this new connection | |
1362 | * to the original PPPD instance. | |
1363 | * And of course, if we don't use irnetd, we can have a race when | |
1364 | * both side try to connect simultaneously, which could leave both | |
1365 | * connections half closed (yuck). | |
1366 | * Conclusions : | |
1367 | * 1) The "originator" must accept the new connection and get rid | |
1368 | * of the old one so that irnetd works | |
1369 | * 2) One side must deny the new connection to avoid races, | |
1370 | * but both side must agree on which side it is... | |
1371 | * Most often, the originator is primary at the LAP layer. | |
1372 | * Jean II | |
1373 | */ | |
1374 | /* Now, let's look at the way I wrote the test... | |
1375 | * We need to clear up the ttp_connect flag atomically to prevent | |
1376 | * irnet_disconnect_indication() to mess up the tsap we are going to close. | |
1377 | * We want to clear the ttp_connect flag only if we close the tsap, | |
1378 | * otherwise we will never close it, so we need to check for primary | |
1379 | * *before* doing the test on the flag. | |
1380 | * And of course, ALLOW_SIMULT_CONNECT can disable this entirely... | |
1381 | * Jean II | |
1382 | */ | |
1383 | ||
1384 | /* Socket already connecting ? On primary ? */ | |
1385 | if(0 | |
1386 | #ifdef ALLOW_SIMULT_CONNECT | |
1387 | || ((irttp_is_primary(server->tsap) == 1) /* primary */ | |
1388 | && (test_and_clear_bit(0, &new->ttp_connect))) | |
1389 | #endif /* ALLOW_SIMULT_CONNECT */ | |
1390 | ) | |
1391 | { | |
1392 | DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n"); | |
1393 | ||
1394 | /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */ | |
1395 | if(new->tsap != NULL) | |
1396 | { | |
1397 | /* Close the old connection the new socket was attempting, | |
1398 | * so that we can hook it up to the new connection. | |
1399 | * It's now safe to do it... */ | |
1400 | irttp_close_tsap(new->tsap); | |
1401 | new->tsap = NULL; | |
1402 | } | |
1403 | } | |
1404 | else | |
1405 | { | |
1406 | /* Three options : | |
1407 | * 1) socket was not connecting or connected : ttp_connect should be 0. | |
1408 | * 2) we don't want to connect the socket because we are secondary or | |
1409 | * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1. | |
1410 | * 3) we are half way in irnet_disconnect_indication(), and it's a | |
1411 | * nice race condition... Fortunately, we can detect that by checking | |
1412 | * if tsap is still alive. On the other hand, we can't be in | |
1413 | * irda_irnet_destroy() otherwise we would not have found this | |
1414 | * socket in the hashbin. | |
1415 | * Jean II */ | |
1416 | if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL)) | |
1417 | { | |
1418 | /* Don't mess this socket, somebody else in in charge... */ | |
1419 | DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n"); | |
1420 | irnet_disconnect_server(server, skb); | |
1421 | return; | |
1422 | } | |
1423 | } | |
1424 | ||
1425 | /* So : at this point, we have a socket, and it is idle. Good ! */ | |
1426 | irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size); | |
1427 | ||
1428 | /* Check size of received packet */ | |
1429 | if(skb->len > 0) | |
1430 | { | |
1431 | #ifdef PASS_CONNECT_PACKETS | |
1432 | DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); | |
1433 | /* Try to pass it to PPP */ | |
1434 | irnet_data_indication(new, new->tsap, skb); | |
1435 | #else /* PASS_CONNECT_PACKETS */ | |
1436 | DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); | |
1437 | kfree_skb(skb); /* Note : will be optimised with other kfree... */ | |
1438 | #endif /* PASS_CONNECT_PACKETS */ | |
1439 | } | |
1440 | else | |
1441 | kfree_skb(skb); | |
1442 | ||
1443 | DEXIT(IRDA_TCB_TRACE, "\n"); | |
1444 | } | |
1445 | ||
1446 | ||
1447 | /********************** IRDA-IAS/LMP CALLBACKS **********************/ | |
1448 | /* | |
1449 | * These are the callbacks called by other layers of the IrDA stack, | |
1450 | * mainly LMP for discovery and IAS for name queries. | |
1451 | */ | |
1452 | ||
1453 | /*------------------------------------------------------------------*/ | |
1454 | /* | |
1455 | * Function irnet_getvalue_confirm (result, obj_id, value, priv) | |
1456 | * | |
1457 | * Got answer from remote LM-IAS, just connect | |
1458 | * | |
1459 | * This is the reply to a IAS query we were doing to find the TSAP of | |
1460 | * the device we want to connect to. | |
1461 | * If we have found a valid TSAP, just initiate the TTP connection | |
1462 | * on this TSAP. | |
1463 | */ | |
1464 | static void | |
1465 | irnet_getvalue_confirm(int result, | |
1466 | __u16 obj_id, | |
1467 | struct ias_value *value, | |
1468 | void * priv) | |
1469 | { | |
1470 | irnet_socket * self = (irnet_socket *) priv; | |
1471 | ||
1472 | DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); | |
1473 | DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); | |
1474 | ||
1475 | /* Check if already connected (via irnet_connect_socket()) | |
1476 | * or socket is closing down (via irda_irnet_destroy()) */ | |
1477 | if(! test_bit(0, &self->ttp_connect)) | |
1478 | { | |
1479 | DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); | |
1480 | return; | |
1481 | } | |
1482 | ||
1483 | /* We probably don't need to make any more queries */ | |
1484 | iriap_close(self->iriap); | |
1485 | self->iriap = NULL; | |
1486 | ||
1487 | /* Post process the IAS reply */ | |
1488 | self->dtsap_sel = irnet_ias_to_tsap(self, result, value); | |
1489 | ||
1490 | /* If error, just go out */ | |
1491 | if(self->errno) | |
1492 | { | |
1493 | clear_bit(0, &self->ttp_connect); | |
1494 | DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno); | |
1495 | return; | |
1496 | } | |
1497 | ||
1498 | DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", | |
1499 | self->daddr, self->dtsap_sel); | |
1500 | ||
1501 | /* Start up TTP - non blocking */ | |
1502 | irnet_connect_tsap(self); | |
1503 | ||
1504 | DEXIT(IRDA_OCB_TRACE, "\n"); | |
1505 | } | |
1506 | ||
1507 | /*------------------------------------------------------------------*/ | |
1508 | /* | |
1509 | * Function irnet_discovervalue_confirm (result, obj_id, value, priv) | |
1510 | * | |
1511 | * Handle the TSAP discovery procedure state machine. | |
1512 | * Got answer from remote LM-IAS, try next device | |
1513 | * | |
1514 | * We are doing a TSAP discovery procedure, and we got an answer to | |
1515 | * a IAS query we were doing to find the TSAP on one of the address | |
1516 | * in the discovery log. | |
1517 | * | |
1518 | * If we have found a valid TSAP for the first time, save it. If it's | |
1519 | * not the first time we found one, complain. | |
1520 | * | |
1521 | * If we have more addresses in the log, just initiate a new query. | |
1522 | * Note that those query may fail (see irnet_discover_daddr_and_lsap_sel()) | |
1523 | * | |
1524 | * Otherwise, wrap up the procedure (cleanup), check if we have found | |
1525 | * any device and connect to it. | |
1526 | */ | |
1527 | static void | |
1528 | irnet_discovervalue_confirm(int result, | |
1529 | __u16 obj_id, | |
1530 | struct ias_value *value, | |
1531 | void * priv) | |
1532 | { | |
1533 | irnet_socket * self = (irnet_socket *) priv; | |
1534 | __u8 dtsap_sel; /* TSAP we are looking for */ | |
1535 | ||
1536 | DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); | |
1537 | DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); | |
1538 | ||
1539 | /* Check if already connected (via irnet_connect_socket()) | |
1540 | * or socket is closing down (via irda_irnet_destroy()) */ | |
1541 | if(! test_bit(0, &self->ttp_connect)) | |
1542 | { | |
1543 | DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); | |
1544 | return; | |
1545 | } | |
1546 | ||
1547 | /* Post process the IAS reply */ | |
1548 | dtsap_sel = irnet_ias_to_tsap(self, result, value); | |
1549 | ||
1550 | /* Have we got something ? */ | |
1551 | if(self->errno == 0) | |
1552 | { | |
1553 | /* We found the requested service */ | |
1554 | if(self->daddr != DEV_ADDR_ANY) | |
1555 | { | |
1556 | DERROR(IRDA_OCB_ERROR, "More than one device in range supports IrNET...\n"); | |
1557 | } | |
1558 | else | |
1559 | { | |
1560 | /* First time we found that one, save it ! */ | |
1561 | self->daddr = self->discoveries[self->disco_index].daddr; | |
1562 | self->dtsap_sel = dtsap_sel; | |
1563 | } | |
1564 | } | |
1565 | ||
1566 | /* If no failure */ | |
1567 | if((self->errno == -EADDRNOTAVAIL) || (self->errno == 0)) | |
1568 | { | |
1569 | int ret; | |
1570 | ||
1571 | /* Search the next node */ | |
1572 | ret = irnet_discover_next_daddr(self); | |
1573 | if(!ret) | |
1574 | { | |
1575 | /* In this case, the above request was non-blocking. | |
1576 | * We will return here after a while... */ | |
1577 | return; | |
1578 | } | |
1579 | /* In this case, we have processed the last discovery item */ | |
1580 | } | |
1581 | ||
1582 | /* No more queries to be done (failure or last one) */ | |
1583 | ||
1584 | /* We probably don't need to make any more queries */ | |
1585 | iriap_close(self->iriap); | |
1586 | self->iriap = NULL; | |
1587 | ||
1588 | /* No more items : remove the log and signal termination */ | |
1589 | DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%p)\n", | |
1590 | self->discoveries); | |
1591 | if(self->discoveries != NULL) | |
1592 | { | |
1593 | /* Cleanup our copy of the discovery log */ | |
1594 | kfree(self->discoveries); | |
1595 | self->discoveries = NULL; | |
1596 | } | |
1597 | self->disco_number = -1; | |
1598 | ||
1599 | /* Check out what we found */ | |
1600 | if(self->daddr == DEV_ADDR_ANY) | |
1601 | { | |
1602 | self->daddr = DEV_ADDR_ANY; | |
1603 | clear_bit(0, &self->ttp_connect); | |
1604 | DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n"); | |
1605 | return; | |
1606 | } | |
1607 | ||
1608 | /* We have a valid address - just connect */ | |
1609 | ||
1610 | DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", | |
1611 | self->daddr, self->dtsap_sel); | |
1612 | ||
1613 | /* Start up TTP - non blocking */ | |
1614 | irnet_connect_tsap(self); | |
1615 | ||
1616 | DEXIT(IRDA_OCB_TRACE, "\n"); | |
1617 | } | |
1618 | ||
1619 | #ifdef DISCOVERY_EVENTS | |
1620 | /*------------------------------------------------------------------*/ | |
1621 | /* | |
1622 | * Function irnet_discovery_indication (discovery) | |
1623 | * | |
1624 | * Got a discovery indication from IrLMP, post an event | |
1625 | * | |
1626 | * Note : IrLMP take care of matching the hint mask for us, and also | |
1627 | * check if it is a "new" node for us... | |
1628 | * | |
1629 | * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET | |
1630 | * nodes, so it's only at connection time that we will know if the | |
1631 | * node support IrNET, IrLAN or both. The other solution is to check | |
1632 | * in IAS the PNP ids and service name. | |
1633 | * Note : even if a node support IrNET (or IrLAN), it's no guarantee | |
1634 | * that we will be able to connect to it, the node might already be | |
1635 | * busy... | |
1636 | * | |
1637 | * One last thing : in some case, this function will trigger duplicate | |
1638 | * discovery events. On the other hand, we should catch all | |
1639 | * discoveries properly (i.e. not miss one). Filtering duplicate here | |
1640 | * is to messy, so we leave that to user space... | |
1641 | */ | |
1642 | static void | |
1643 | irnet_discovery_indication(discinfo_t * discovery, | |
1644 | DISCOVERY_MODE mode, | |
1645 | void * priv) | |
1646 | { | |
1647 | irnet_socket * self = &irnet_server.s; | |
1648 | ||
1649 | DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); | |
1650 | DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, | |
1651 | "Invalid instance (0x%p) !!!\n", priv); | |
1652 | ||
1653 | DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n", | |
1654 | discovery->info); | |
1655 | ||
1656 | /* Notify the control channel */ | |
1657 | irnet_post_event(NULL, IRNET_DISCOVER, | |
1658 | discovery->saddr, discovery->daddr, discovery->info, | |
1659 | u16ho(discovery->hints)); | |
1660 | ||
1661 | DEXIT(IRDA_OCB_TRACE, "\n"); | |
1662 | } | |
1663 | ||
1664 | /*------------------------------------------------------------------*/ | |
1665 | /* | |
1666 | * Function irnet_expiry_indication (expiry) | |
1667 | * | |
1668 | * Got a expiry indication from IrLMP, post an event | |
1669 | * | |
1670 | * Note : IrLMP take care of matching the hint mask for us, we only | |
1671 | * check if it is a "new" node... | |
1672 | */ | |
1673 | static void | |
1674 | irnet_expiry_indication(discinfo_t * expiry, | |
1675 | DISCOVERY_MODE mode, | |
1676 | void * priv) | |
1677 | { | |
1678 | irnet_socket * self = &irnet_server.s; | |
1679 | ||
1680 | DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); | |
1681 | DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, | |
1682 | "Invalid instance (0x%p) !!!\n", priv); | |
1683 | ||
1684 | DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n", | |
1685 | expiry->info); | |
1686 | ||
1687 | /* Notify the control channel */ | |
1688 | irnet_post_event(NULL, IRNET_EXPIRE, | |
1689 | expiry->saddr, expiry->daddr, expiry->info, | |
1690 | u16ho(expiry->hints)); | |
1691 | ||
1692 | DEXIT(IRDA_OCB_TRACE, "\n"); | |
1693 | } | |
1694 | #endif /* DISCOVERY_EVENTS */ | |
1695 | ||
1696 | ||
1697 | /*********************** PROC ENTRY CALLBACKS ***********************/ | |
1698 | /* | |
1699 | * We create a instance in the /proc filesystem, and here we take care | |
1700 | * of that... | |
1701 | */ | |
1702 | ||
1703 | #ifdef CONFIG_PROC_FS | |
1704 | /*------------------------------------------------------------------*/ | |
1705 | /* | |
1706 | * Function irnet_proc_read (buf, start, offset, len, unused) | |
1707 | * | |
1708 | * Give some info to the /proc file system | |
1709 | */ | |
1710 | static int | |
1711 | irnet_proc_read(char * buf, | |
1712 | char ** start, | |
1713 | off_t offset, | |
1714 | int len) | |
1715 | { | |
1716 | irnet_socket * self; | |
1717 | char * state; | |
1718 | int i = 0; | |
1719 | ||
1720 | len = 0; | |
1721 | ||
1722 | /* Get the IrNET server information... */ | |
1723 | len += sprintf(buf+len, "IrNET server - "); | |
1724 | len += sprintf(buf+len, "IrDA state: %s, ", | |
1725 | (irnet_server.running ? "running" : "dead")); | |
1726 | len += sprintf(buf+len, "stsap_sel: %02x, ", irnet_server.s.stsap_sel); | |
1727 | len += sprintf(buf+len, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel); | |
1728 | ||
1729 | /* Do we need to continue ? */ | |
1730 | if(!irnet_server.running) | |
1731 | return len; | |
1732 | ||
1733 | /* Protect access to the instance list */ | |
1734 | spin_lock_bh(&irnet_server.spinlock); | |
1735 | ||
1736 | /* Get the sockets one by one... */ | |
1737 | self = (irnet_socket *) hashbin_get_first(irnet_server.list); | |
1738 | while(self != NULL) | |
1739 | { | |
1740 | /* Start printing info about the socket. */ | |
1741 | len += sprintf(buf+len, "\nIrNET socket %d - ", i++); | |
1742 | ||
1743 | /* First, get the requested configuration */ | |
1744 | len += sprintf(buf+len, "Requested IrDA name: \"%s\", ", self->rname); | |
1745 | len += sprintf(buf+len, "daddr: %08x, ", self->rdaddr); | |
1746 | len += sprintf(buf+len, "saddr: %08x\n", self->rsaddr); | |
1747 | ||
1748 | /* Second, get all the PPP info */ | |
1749 | len += sprintf(buf+len, " PPP state: %s", | |
1750 | (self->ppp_open ? "registered" : "unregistered")); | |
1751 | if(self->ppp_open) | |
1752 | { | |
1753 | len += sprintf(buf+len, ", unit: ppp%d", | |
1754 | ppp_unit_number(&self->chan)); | |
1755 | len += sprintf(buf+len, ", channel: %d", | |
1756 | ppp_channel_index(&self->chan)); | |
1757 | len += sprintf(buf+len, ", mru: %d", | |
1758 | self->mru); | |
1759 | /* Maybe add self->flags ? Later... */ | |
1760 | } | |
1761 | ||
1762 | /* Then, get all the IrDA specific info... */ | |
1763 | if(self->ttp_open) | |
1764 | state = "connected"; | |
1765 | else | |
1766 | if(self->tsap != NULL) | |
1767 | state = "connecting"; | |
1768 | else | |
1769 | if(self->iriap != NULL) | |
1770 | state = "searching"; | |
1771 | else | |
1772 | if(self->ttp_connect) | |
1773 | state = "weird"; | |
1774 | else | |
1775 | state = "idle"; | |
1776 | len += sprintf(buf+len, "\n IrDA state: %s, ", state); | |
1777 | len += sprintf(buf+len, "daddr: %08x, ", self->daddr); | |
1778 | len += sprintf(buf+len, "stsap_sel: %02x, ", self->stsap_sel); | |
1779 | len += sprintf(buf+len, "dtsap_sel: %02x\n", self->dtsap_sel); | |
1780 | ||
1781 | /* Next socket, please... */ | |
1782 | self = (irnet_socket *) hashbin_get_next(irnet_server.list); | |
1783 | } | |
1784 | ||
1785 | /* Spin lock end */ | |
1786 | spin_unlock_bh(&irnet_server.spinlock); | |
1787 | ||
1788 | return len; | |
1789 | } | |
1790 | #endif /* PROC_FS */ | |
1791 | ||
1792 | ||
1793 | /********************** CONFIGURATION/CLEANUP **********************/ | |
1794 | /* | |
1795 | * Initialisation and teardown of the IrDA part, called at module | |
1796 | * insertion and removal... | |
1797 | */ | |
1798 | ||
1799 | /*------------------------------------------------------------------*/ | |
1800 | /* | |
1801 | * Prepare the IrNET layer for operation... | |
1802 | */ | |
1803 | int __init | |
1804 | irda_irnet_init(void) | |
1805 | { | |
1806 | int err = 0; | |
1807 | ||
1808 | DENTER(MODULE_TRACE, "()\n"); | |
1809 | ||
1810 | /* Pure paranoia - should be redundant */ | |
1811 | memset(&irnet_server, 0, sizeof(struct irnet_root)); | |
1812 | ||
1813 | /* Setup start of irnet instance list */ | |
1814 | irnet_server.list = hashbin_new(HB_NOLOCK); | |
1815 | DABORT(irnet_server.list == NULL, -ENOMEM, | |
1816 | MODULE_ERROR, "Can't allocate hashbin!\n"); | |
1817 | /* Init spinlock for instance list */ | |
1818 | spin_lock_init(&irnet_server.spinlock); | |
1819 | ||
1820 | /* Initialise control channel */ | |
1821 | init_waitqueue_head(&irnet_events.rwait); | |
1822 | irnet_events.index = 0; | |
1823 | /* Init spinlock for event logging */ | |
1824 | spin_lock_init(&irnet_events.spinlock); | |
1825 | ||
1826 | #ifdef CONFIG_PROC_FS | |
1827 | /* Add a /proc file for irnet infos */ | |
1828 | create_proc_info_entry("irnet", 0, proc_irda, irnet_proc_read); | |
1829 | #endif /* CONFIG_PROC_FS */ | |
1830 | ||
1831 | /* Setup the IrNET server */ | |
1832 | err = irnet_setup_server(); | |
1833 | ||
1834 | if(!err) | |
1835 | /* We are no longer functional... */ | |
1836 | irnet_server.running = 1; | |
1837 | ||
1838 | DEXIT(MODULE_TRACE, "\n"); | |
1839 | return err; | |
1840 | } | |
1841 | ||
1842 | /*------------------------------------------------------------------*/ | |
1843 | /* | |
1844 | * Cleanup at exit... | |
1845 | */ | |
1846 | void __exit | |
1847 | irda_irnet_cleanup(void) | |
1848 | { | |
1849 | DENTER(MODULE_TRACE, "()\n"); | |
1850 | ||
1851 | /* We are no longer there... */ | |
1852 | irnet_server.running = 0; | |
1853 | ||
1854 | #ifdef CONFIG_PROC_FS | |
1855 | /* Remove our /proc file */ | |
1856 | remove_proc_entry("irnet", proc_irda); | |
1857 | #endif /* CONFIG_PROC_FS */ | |
1858 | ||
1859 | /* Remove our IrNET server from existence */ | |
1860 | irnet_destroy_server(); | |
1861 | ||
1862 | /* Remove all instances of IrNET socket still present */ | |
1863 | hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy); | |
1864 | ||
1865 | DEXIT(MODULE_TRACE, "\n"); | |
1866 | } |