~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/irda/irlan/irlan_client.c

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*********************************************************************
  2  *
  3  * Filename:      irlan_client.c
  4  * Version:       0.9
  5  * Description:   IrDA LAN Access Protocol (IrLAN) Client
  6  * Status:        Experimental.
  7  * Author:        Dag Brattli <dagb@cs.uit.no>
  8  * Created at:    Sun Aug 31 20:14:37 1997
  9  * Modified at:   Tue Dec 14 15:47:02 1999
 10  * Modified by:   Dag Brattli <dagb@cs.uit.no>
 11  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
 12  *                slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
 13  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
 14  *
 15  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
 16  *     All Rights Reserved.
 17  *
 18  *     This program is free software; you can redistribute it and/or
 19  *     modify it under the terms of the GNU General Public License as
 20  *     published by the Free Software Foundation; either version 2 of
 21  *     the License, or (at your option) any later version.
 22  *
 23  *     Neither Dag Brattli nor University of Tromsø admit liability nor
 24  *     provide warranty for any of this software. This material is
 25  *     provided "AS-IS" and at no charge.
 26  *
 27  ********************************************************************/
 28 
 29 #include <linux/kernel.h>
 30 #include <linux/string.h>
 31 #include <linux/slab.h>
 32 #include <linux/errno.h>
 33 #include <linux/init.h>
 34 #include <linux/netdevice.h>
 35 #include <linux/etherdevice.h>
 36 #include <linux/if_arp.h>
 37 #include <linux/bitops.h>
 38 #include <net/arp.h>
 39 
 40 #include <asm/byteorder.h>
 41 
 42 #include <net/irda/irda.h>
 43 #include <net/irda/irttp.h>
 44 #include <net/irda/irlmp.h>
 45 #include <net/irda/irias_object.h>
 46 #include <net/irda/iriap.h>
 47 #include <net/irda/timer.h>
 48 
 49 #include <net/irda/irlan_common.h>
 50 #include <net/irda/irlan_event.h>
 51 #include <net/irda/irlan_eth.h>
 52 #include <net/irda/irlan_provider.h>
 53 #include <net/irda/irlan_client.h>
 54 
 55 #undef CONFIG_IRLAN_GRATUITOUS_ARP
 56 
 57 static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
 58                                                     LM_REASON reason,
 59                                                     struct sk_buff *);
 60 static int irlan_client_ctrl_data_indication(void *instance, void *sap,
 61                                              struct sk_buff *skb);
 62 static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
 63                                               struct qos_info *qos,
 64                                               __u32 max_sdu_size,
 65                                               __u8 max_header_size,
 66                                               struct sk_buff *);
 67 static void irlan_check_response_param(struct irlan_cb *self, char *param,
 68                                        char *value, int val_len);
 69 static void irlan_client_open_ctrl_tsap(struct irlan_cb *self);
 70 
 71 static void irlan_client_kick_timer_expired(void *data)
 72 {
 73         struct irlan_cb *self = (struct irlan_cb *) data;
 74 
 75         IRDA_ASSERT(self != NULL, return;);
 76         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 77 
 78         /*
 79          * If we are in peer mode, the client may not have got the discovery
 80          * indication it needs to make progress. If the client is still in
 81          * IDLE state, we must kick it to, but only if the provider is not IDLE
 82          */
 83         if ((self->provider.access_type == ACCESS_PEER) &&
 84             (self->client.state == IRLAN_IDLE) &&
 85             (self->provider.state != IRLAN_IDLE)) {
 86                 irlan_client_wakeup(self, self->saddr, self->daddr);
 87         }
 88 }
 89 
 90 static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
 91 {
 92         irda_start_timer(&self->client.kick_timer, timeout, (void *) self,
 93                          irlan_client_kick_timer_expired);
 94 }
 95 
 96 /*
 97  * Function irlan_client_wakeup (self, saddr, daddr)
 98  *
 99  *    Wake up client
100  *
101  */
102 void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
103 {
104         IRDA_ASSERT(self != NULL, return;);
105         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
106 
107         /*
108          * Check if we are already awake, or if we are a provider in direct
109          * mode (in that case we must leave the client idle
110          */
111         if ((self->client.state != IRLAN_IDLE) ||
112             (self->provider.access_type == ACCESS_DIRECT))
113         {
114                 pr_debug("%s(), already awake!\n", __func__);
115                         return;
116         }
117 
118         /* Addresses may have changed! */
119         self->saddr = saddr;
120         self->daddr = daddr;
121 
122         if (self->disconnect_reason == LM_USER_REQUEST) {
123                 pr_debug("%s(), still stopped by user\n", __func__);
124                         return;
125         }
126 
127         /* Open TSAPs */
128         irlan_client_open_ctrl_tsap(self);
129         irlan_open_data_tsap(self);
130 
131         irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
132 
133         /* Start kick timer */
134         irlan_client_start_kick_timer(self, 2*HZ);
135 }
136 
137 /*
138  * Function irlan_discovery_indication (daddr)
139  *
140  *    Remote device with IrLAN server support discovered
141  *
142  */
143 void irlan_client_discovery_indication(discinfo_t *discovery,
144                                        DISCOVERY_MODE mode,
145                                        void *priv)
146 {
147         struct irlan_cb *self;
148         __u32 saddr, daddr;
149 
150         IRDA_ASSERT(discovery != NULL, return;);
151 
152         /*
153          * I didn't check it, but I bet that IrLAN suffer from the same
154          * deficiency as IrComm and doesn't handle two instances
155          * simultaneously connecting to each other.
156          * Same workaround, drop passive discoveries.
157          * Jean II */
158         if(mode == DISCOVERY_PASSIVE)
159                 return;
160 
161         saddr = discovery->saddr;
162         daddr = discovery->daddr;
163 
164         /* Find instance */
165         rcu_read_lock();
166         self = irlan_get_any();
167         if (self) {
168                 IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;);
169 
170                 pr_debug("%s(), Found instance (%08x)!\n", __func__ ,
171                          daddr);
172 
173                 irlan_client_wakeup(self, saddr, daddr);
174         }
175 IRDA_ASSERT_LABEL(out:)
176         rcu_read_unlock();
177 }
178 
179 /*
180  * Function irlan_client_data_indication (handle, skb)
181  *
182  *    This function gets the data that is received on the control channel
183  *
184  */
185 static int irlan_client_ctrl_data_indication(void *instance, void *sap,
186                                              struct sk_buff *skb)
187 {
188         struct irlan_cb *self;
189 
190         self = instance;
191 
192         IRDA_ASSERT(self != NULL, return -1;);
193         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
194         IRDA_ASSERT(skb != NULL, return -1;);
195 
196         irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
197 
198         /* Ready for a new command */
199         pr_debug("%s(), clearing tx_busy\n", __func__);
200         self->client.tx_busy = FALSE;
201 
202         /* Check if we have some queued commands waiting to be sent */
203         irlan_run_ctrl_tx_queue(self);
204 
205         return 0;
206 }
207 
208 static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
209                                                     LM_REASON reason,
210                                                     struct sk_buff *userdata)
211 {
212         struct irlan_cb *self;
213         struct tsap_cb *tsap;
214         struct sk_buff *skb;
215 
216         pr_debug("%s(), reason=%d\n", __func__ , reason);
217 
218         self = instance;
219         tsap = sap;
220 
221         IRDA_ASSERT(self != NULL, return;);
222         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
223         IRDA_ASSERT(tsap != NULL, return;);
224         IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
225 
226         IRDA_ASSERT(tsap == self->client.tsap_ctrl, return;);
227 
228         /* Remove frames queued on the control channel */
229         while ((skb = skb_dequeue(&self->client.txq)) != NULL) {
230                 dev_kfree_skb(skb);
231         }
232         self->client.tx_busy = FALSE;
233 
234         irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
235 }
236 
237 /*
238  * Function irlan_client_open_tsaps (self)
239  *
240  *    Initialize callbacks and open IrTTP TSAPs
241  *
242  */
243 static void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
244 {
245         struct tsap_cb *tsap;
246         notify_t notify;
247 
248         IRDA_ASSERT(self != NULL, return;);
249         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
250 
251         /* Check if already open */
252         if (self->client.tsap_ctrl)
253                 return;
254 
255         irda_notify_init(&notify);
256 
257         /* Set up callbacks */
258         notify.data_indication       = irlan_client_ctrl_data_indication;
259         notify.connect_confirm       = irlan_client_ctrl_connect_confirm;
260         notify.disconnect_indication = irlan_client_ctrl_disconnect_indication;
261         notify.instance = self;
262         strlcpy(notify.name, "IrLAN ctrl (c)", sizeof(notify.name));
263 
264         tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
265         if (!tsap) {
266                 pr_debug("%s(), Got no tsap!\n", __func__);
267                 return;
268         }
269         self->client.tsap_ctrl = tsap;
270 }
271 
272 /*
273  * Function irlan_client_connect_confirm (handle, skb)
274  *
275  *    Connection to peer IrLAN laye confirmed
276  *
277  */
278 static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
279                                               struct qos_info *qos,
280                                               __u32 max_sdu_size,
281                                               __u8 max_header_size,
282                                               struct sk_buff *skb)
283 {
284         struct irlan_cb *self;
285 
286         self = instance;
287 
288         IRDA_ASSERT(self != NULL, return;);
289         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
290 
291         self->client.max_sdu_size = max_sdu_size;
292         self->client.max_header_size = max_header_size;
293 
294         /* TODO: we could set the MTU depending on the max_sdu_size */
295 
296         irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL);
297 }
298 
299 /*
300  * Function print_ret_code (code)
301  *
302  *    Print return code of request to peer IrLAN layer.
303  *
304  */
305 static void print_ret_code(__u8 code)
306 {
307         switch(code) {
308         case 0:
309                 printk(KERN_INFO "Success\n");
310                 break;
311         case 1:
312                 net_warn_ratelimited("IrLAN: Insufficient resources\n");
313                 break;
314         case 2:
315                 net_warn_ratelimited("IrLAN: Invalid command format\n");
316                 break;
317         case 3:
318                 net_warn_ratelimited("IrLAN: Command not supported\n");
319                 break;
320         case 4:
321                 net_warn_ratelimited("IrLAN: Parameter not supported\n");
322                 break;
323         case 5:
324                 net_warn_ratelimited("IrLAN: Value not supported\n");
325                 break;
326         case 6:
327                 net_warn_ratelimited("IrLAN: Not open\n");
328                 break;
329         case 7:
330                 net_warn_ratelimited("IrLAN: Authentication required\n");
331                 break;
332         case 8:
333                 net_warn_ratelimited("IrLAN: Invalid password\n");
334                 break;
335         case 9:
336                 net_warn_ratelimited("IrLAN: Protocol error\n");
337                 break;
338         case 255:
339                 net_warn_ratelimited("IrLAN: Asynchronous status\n");
340                 break;
341         }
342 }
343 
344 /*
345  * Function irlan_client_parse_response (self, skb)
346  *
347  *    Extract all parameters from received buffer, then feed them to
348  *    check_params for parsing
349  */
350 void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
351 {
352         __u8 *frame;
353         __u8 *ptr;
354         int count;
355         int ret;
356         __u16 val_len;
357         int i;
358         char *name;
359         char *value;
360 
361         IRDA_ASSERT(skb != NULL, return;);
362 
363         pr_debug("%s() skb->len=%d\n", __func__ , (int)skb->len);
364 
365         IRDA_ASSERT(self != NULL, return;);
366         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
367 
368         if (!skb) {
369                 net_err_ratelimited("%s(), Got NULL skb!\n", __func__);
370                 return;
371         }
372         frame = skb->data;
373 
374         /*
375          *  Check return code and print it if not success
376          */
377         if (frame[0]) {
378                 print_ret_code(frame[0]);
379                 return;
380         }
381 
382         name = kmalloc(255, GFP_ATOMIC);
383         if (!name)
384                 return;
385         value = kmalloc(1016, GFP_ATOMIC);
386         if (!value) {
387                 kfree(name);
388                 return;
389         }
390 
391         /* How many parameters? */
392         count = frame[1];
393 
394         pr_debug("%s(), got %d parameters\n", __func__ , count);
395 
396         ptr = frame+2;
397 
398         /* For all parameters */
399         for (i=0; i<count;i++) {
400                 ret = irlan_extract_param(ptr, name, value, &val_len);
401                 if (ret < 0) {
402                         pr_debug("%s(), IrLAN, Error!\n", __func__);
403                         break;
404                 }
405                 ptr += ret;
406                 irlan_check_response_param(self, name, value, val_len);
407         }
408         /* Cleanup */
409         kfree(name);
410         kfree(value);
411 }
412 
413 /*
414  * Function irlan_check_response_param (self, param, value, val_len)
415  *
416  *     Check which parameter is received and update local variables
417  *
418  */
419 static void irlan_check_response_param(struct irlan_cb *self, char *param,
420                                        char *value, int val_len)
421 {
422         __u16 tmp_cpu; /* Temporary value in host order */
423         __u8 *bytes;
424         int i;
425 
426         pr_debug("%s(), parm=%s\n", __func__ , param);
427 
428         IRDA_ASSERT(self != NULL, return;);
429         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
430 
431         /* Media type */
432         if (strcmp(param, "MEDIA") == 0) {
433                 if (strcmp(value, "802.3") == 0)
434                         self->media = MEDIA_802_3;
435                 else
436                         self->media = MEDIA_802_5;
437                 return;
438         }
439         if (strcmp(param, "FILTER_TYPE") == 0) {
440                 if (strcmp(value, "DIRECTED") == 0)
441                         self->client.filter_type |= IRLAN_DIRECTED;
442                 else if (strcmp(value, "FUNCTIONAL") == 0)
443                         self->client.filter_type |= IRLAN_FUNCTIONAL;
444                 else if (strcmp(value, "GROUP") == 0)
445                         self->client.filter_type |= IRLAN_GROUP;
446                 else if (strcmp(value, "MAC_FRAME") == 0)
447                         self->client.filter_type |= IRLAN_MAC_FRAME;
448                 else if (strcmp(value, "MULTICAST") == 0)
449                         self->client.filter_type |= IRLAN_MULTICAST;
450                 else if (strcmp(value, "BROADCAST") == 0)
451                         self->client.filter_type |= IRLAN_BROADCAST;
452                 else if (strcmp(value, "IPX_SOCKET") == 0)
453                         self->client.filter_type |= IRLAN_IPX_SOCKET;
454 
455         }
456         if (strcmp(param, "ACCESS_TYPE") == 0) {
457                 if (strcmp(value, "DIRECT") == 0)
458                         self->client.access_type = ACCESS_DIRECT;
459                 else if (strcmp(value, "PEER") == 0)
460                         self->client.access_type = ACCESS_PEER;
461                 else if (strcmp(value, "HOSTED") == 0)
462                         self->client.access_type = ACCESS_HOSTED;
463                 else {
464                         pr_debug("%s(), unknown access type!\n", __func__);
465                 }
466         }
467         /* IRLAN version */
468         if (strcmp(param, "IRLAN_VER") == 0) {
469                 pr_debug("IrLAN version %d.%d\n", (__u8)value[0],
470                          (__u8)value[1]);
471 
472                 self->version[0] = value[0];
473                 self->version[1] = value[1];
474                 return;
475         }
476         /* Which remote TSAP to use for data channel */
477         if (strcmp(param, "DATA_CHAN") == 0) {
478                 self->dtsap_sel_data = value[0];
479                 pr_debug("Data TSAP = %02x\n", self->dtsap_sel_data);
480                 return;
481         }
482         if (strcmp(param, "CON_ARB") == 0) {
483                 memcpy(&tmp_cpu, value, 2); /* Align value */
484                 le16_to_cpus(&tmp_cpu);     /* Convert to host order */
485                 self->client.recv_arb_val = tmp_cpu;
486                 pr_debug("%s(), receive arb val=%d\n", __func__ ,
487                          self->client.recv_arb_val);
488         }
489         if (strcmp(param, "MAX_FRAME") == 0) {
490                 memcpy(&tmp_cpu, value, 2); /* Align value */
491                 le16_to_cpus(&tmp_cpu);     /* Convert to host order */
492                 self->client.max_frame = tmp_cpu;
493                 pr_debug("%s(), max frame=%d\n", __func__ ,
494                          self->client.max_frame);
495         }
496 
497         /* RECONNECT_KEY, in case the link goes down! */
498         if (strcmp(param, "RECONNECT_KEY") == 0) {
499                 pr_debug("Got reconnect key: ");
500                 /* for (i = 0; i < val_len; i++) */
501 /*                      printk("%02x", value[i]); */
502                 memcpy(self->client.reconnect_key, value, val_len);
503                 self->client.key_len = val_len;
504                 pr_debug("\n");
505         }
506         /* FILTER_ENTRY, have we got an ethernet address? */
507         if (strcmp(param, "FILTER_ENTRY") == 0) {
508                 bytes = value;
509                 pr_debug("Ethernet address = %pM\n", bytes);
510                 for (i = 0; i < 6; i++)
511                         self->dev->dev_addr[i] = bytes[i];
512         }
513 }
514 
515 /*
516  * Function irlan_client_get_value_confirm (obj_id, value)
517  *
518  *    Got results from remote LM-IAS
519  *
520  */
521 void irlan_client_get_value_confirm(int result, __u16 obj_id,
522                                     struct ias_value *value, void *priv)
523 {
524         struct irlan_cb *self;
525 
526         IRDA_ASSERT(priv != NULL, return;);
527 
528         self = priv;
529         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
530 
531         /* We probably don't need to make any more queries */
532         iriap_close(self->client.iriap);
533         self->client.iriap = NULL;
534 
535         /* Check if request succeeded */
536         if (result != IAS_SUCCESS) {
537                 pr_debug("%s(), got NULL value!\n", __func__);
538                 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
539                                       NULL);
540                 return;
541         }
542 
543         switch (value->type) {
544         case IAS_INTEGER:
545                 self->dtsap_sel_ctrl = value->t.integer;
546 
547                 if (value->t.integer != -1) {
548                         irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL,
549                                               NULL);
550                         return;
551                 }
552                 irias_delete_value(value);
553                 break;
554         default:
555                 pr_debug("%s(), unknown type!\n", __func__);
556                 break;
557         }
558         irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
559 }
560 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp