diff options
Diffstat (limited to 'net/irda/irnet/irnet_irda.c')
-rw-r--r-- | net/irda/irnet/irnet_irda.c | 1866 |
1 files changed, 1866 insertions, 0 deletions
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c new file mode 100644 index 000000000000..07ec326c71f5 --- /dev/null +++ b/net/irda/irnet/irnet_irda.c | |||
@@ -0,0 +1,1866 @@ | |||
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)); | ||
699 | self->rname[NICKNAME_MAX_LEN + 1] = '\0'; | ||
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 | } | ||