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

Linux Cross Reference
Linux/net/irda/irlap_frame.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*********************************************************************
  2  *                
  3  * Filename:      irlap_frame.c
  4  * Version:       1.0
  5  * Description:   Build and transmit IrLAP frames
  6  * Status:        Stable
  7  * Author:        Dag Brattli <dagb@cs.uit.no>
  8  * Created at:    Tue Aug 19 10:27:26 1997
  9  * Modified at:   Wed Jan  5 08:59:04 2000
 10  * Modified by:   Dag Brattli <dagb@cs.uit.no>
 11  * 
 12  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
 13  *     All Rights Reserved.
 14  *     
 15  *     This program is free software; you can redistribute it and/or 
 16  *     modify it under the terms of the GNU General Public License as 
 17  *     published by the Free Software Foundation; either version 2 of 
 18  *     the License, or (at your option) any later version.
 19  *
 20  *     Neither Dag Brattli nor University of Tromsų admit liability nor
 21  *     provide warranty for any of this software. This material is 
 22  *     provided "AS-IS" and at no charge.
 23  *
 24  ********************************************************************/
 25 
 26 #include <linux/skbuff.h>
 27 #include <linux/if.h>
 28 #include <linux/if_ether.h>
 29 #include <linux/netdevice.h>
 30 #include <linux/irda.h>
 31  
 32 #include <net/pkt_sched.h>
 33 #include <net/sock.h>
 34  
 35 #include <asm/byteorder.h>
 36 
 37 #include <net/irda/irda.h>
 38 #include <net/irda/irda_device.h>
 39 #include <net/irda/irlap.h>
 40 #include <net/irda/wrapper.h>
 41 #include <net/irda/timer.h>
 42 #include <net/irda/irlap_frame.h>
 43 #include <net/irda/qos.h>
 44 
 45 /*
 46  * Function irlap_insert_info (self, skb)
 47  *
 48  *    Insert minimum turnaround time and speed information into the skb. We 
 49  *    need to do this since it's per packet relevant information. Safe to
 50  *    have this function inlined since it's only called from one place
 51  */
 52 static inline void irlap_insert_info(struct irlap_cb *self, 
 53                                      struct sk_buff *skb)
 54 {
 55         struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
 56 
 57         /*  
 58          * Insert MTT (min. turn time) and speed into skb, so that the
 59          * device driver knows which settings to use 
 60          */
 61         cb->magic = LAP_MAGIC;
 62         cb->mtt = self->mtt_required;
 63         cb->speed = self->speed;
 64 
 65         /* Reset */
 66         self->mtt_required = 0;
 67         
 68         /* 
 69          * Delay equals negotiated BOFs count, plus the number of BOFs to 
 70          * force the negotiated minimum turnaround time 
 71          */
 72         cb->xbofs = self->bofs_count;
 73         cb->xbofs_delay = self->xbofs_delay;
 74         
 75         /* Reset XBOF's delay (used only for getting min turn time) */
 76         self->xbofs_delay = 0;
 77 }
 78 
 79 /*
 80  * Function irlap_queue_xmit (self, skb)
 81  *
 82  *    A little wrapper for dev_queue_xmit, so we can insert some common
 83  *    code into it.
 84  */
 85 void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
 86 {
 87         /* Some common init stuff */
 88         skb->dev = self->netdev;
 89         skb->h.raw = skb->nh.raw = skb->mac.raw = skb->data;
 90         skb->protocol = htons(ETH_P_IRDA);
 91         skb->priority = TC_PRIO_BESTEFFORT;
 92 
 93         irlap_insert_info(self, skb);
 94 
 95         dev_queue_xmit(skb);
 96 }
 97 
 98 /*
 99  * Function irlap_send_snrm_cmd (void)
100  *
101  *    Transmits a connect SNRM command frame
102  */
103 void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) 
104 {
105         struct sk_buff *skb;
106         struct snrm_frame *frame;
107         int ret;
108 
109         ASSERT(self != NULL, return;);
110         ASSERT(self->magic == LAP_MAGIC, return;);
111 
112         /* Allocate frame */
113         skb = dev_alloc_skb(64);
114         if (!skb)
115                 return;
116 
117         frame = (struct snrm_frame *) skb_put(skb, 2); 
118 
119         /* Insert connection address field */
120         if (qos)
121                 frame->caddr = CMD_FRAME | CBROADCAST;
122         else
123                 frame->caddr = CMD_FRAME | self->caddr;
124 
125         /* Insert control field */
126         frame->control = SNRM_CMD | PF_BIT;
127         
128         /*
129          *  If we are establishing a connection then insert QoS paramerters 
130          */
131         if (qos) {
132                 skb_put(skb, 9); /* 21 left */
133                 frame->saddr = cpu_to_le32(self->saddr);
134                 frame->daddr = cpu_to_le32(self->daddr);
135 
136                 frame->ncaddr = self->caddr;
137                                 
138                 ret = irlap_insert_qos_negotiation_params(self, skb);
139                 if (ret < 0) {
140                         dev_kfree_skb(skb);
141                         return;
142                 }
143         }
144         irlap_queue_xmit(self, skb);
145 }
146 
147 /*
148  * Function irlap_recv_snrm_cmd (skb, info)
149  *
150  *    Received SNRM (Set Normal Response Mode) command frame
151  *
152  */
153 static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, 
154                                 struct irlap_info *info) 
155 {
156         struct snrm_frame *frame;
157 
158         frame = (struct snrm_frame *) skb->data;
159         
160         if (skb->len >= sizeof(struct snrm_frame)) {
161                 /* Copy the new connection address */
162                 info->caddr = frame->ncaddr;
163 
164                 /* Check if the new connection address is valid */
165                 if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
166                         IRDA_DEBUG(3, __FUNCTION__ 
167                               "(), invalid connection address!\n");
168                         return;
169                 }
170                 
171                 /* Copy peer device address */
172                 info->daddr = le32_to_cpu(frame->saddr);
173                 info->saddr = le32_to_cpu(frame->daddr);
174                 
175                 /* Only accept if addressed directly to us */
176                 if (info->saddr != self->saddr) {
177                         IRDA_DEBUG(2, __FUNCTION__ "(), not addressed to us!\n");
178                         return;
179                 }
180                 irlap_do_event(self, RECV_SNRM_CMD, skb, info);
181         } else {
182                 /* Signal that this SNRM frame does not contain and I-field */
183                 irlap_do_event(self, RECV_SNRM_CMD, skb, NULL);
184         }
185 }
186 
187 /*
188  * Function irlap_send_ua_response_frame (qos)
189  *
190  *    Send UA (Unnumbered Acknowledgement) frame
191  *
192  */
193 void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
194 {
195         struct sk_buff *skb;
196         struct ua_frame *frame;
197         int ret;
198         
199         IRDA_DEBUG(2, __FUNCTION__ "() <%ld>\n", jiffies);
200         
201         ASSERT(self != NULL, return;);
202         ASSERT(self->magic == LAP_MAGIC, return;);
203 
204         skb = NULL;
205 
206         /* Allocate frame */
207         skb = dev_alloc_skb(64);
208         if (!skb)
209                 return;
210 
211         frame = (struct ua_frame *) skb_put(skb, 10);
212         
213         /* Build UA response */
214         frame->caddr = self->caddr;
215         frame->control = UA_RSP | PF_BIT;
216 
217         frame->saddr = cpu_to_le32(self->saddr);
218         frame->daddr = cpu_to_le32(self->daddr);
219 
220         /* Should we send QoS negotiation parameters? */
221         if (qos) {
222                 ret = irlap_insert_qos_negotiation_params(self, skb);
223                 if (ret < 0) {
224                         dev_kfree_skb(skb);
225                         return;
226                 }
227         }
228 
229         irlap_queue_xmit(self, skb);
230 }
231 
232 
233 /*
234  * Function irlap_send_dm_frame (void)
235  *
236  *    Send disconnected mode (DM) frame
237  *
238  */
239 void irlap_send_dm_frame( struct irlap_cb *self)
240 {
241         struct sk_buff *skb = NULL;
242         __u8 *frame;
243         
244         ASSERT(self != NULL, return;);
245         ASSERT(self->magic == LAP_MAGIC, return;);
246 
247         skb = dev_alloc_skb(32);
248         if (!skb)
249                 return;
250 
251         frame = skb_put( skb, 2);
252         
253         if (self->state == LAP_NDM)
254                 frame[0] = CBROADCAST;
255         else
256                 frame[0] = self->caddr;
257 
258         frame[1] = DM_RSP | PF_BIT;
259 
260         irlap_queue_xmit(self, skb);    
261 }
262 
263 /*
264  * Function irlap_send_disc_frame (void)
265  *
266  *    Send disconnect (DISC) frame
267  *
268  */
269 void irlap_send_disc_frame(struct irlap_cb *self) 
270 {
271         struct sk_buff *skb = NULL;
272         __u8 *frame;
273         
274         IRDA_DEBUG(3, __FUNCTION__ "()\n");
275 
276         ASSERT(self != NULL, return;);
277         ASSERT(self->magic == LAP_MAGIC, return;);
278 
279         skb = dev_alloc_skb(16);
280         if (!skb)
281                 return;
282 
283         frame = skb_put(skb, 2);
284         
285         frame[0] = self->caddr | CMD_FRAME;
286         frame[1] = DISC_CMD | PF_BIT;
287 
288         irlap_queue_xmit(self, skb);
289 }
290 
291 /*
292  * Function irlap_send_discovery_xid_frame (S, s, command)
293  *
294  *    Build and transmit a XID (eXchange station IDentifier) discovery
295  *    frame. 
296  */
297 void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, 
298                                     __u8 command, discovery_t *discovery) 
299 {
300         struct sk_buff *skb = NULL;
301         struct xid_frame *frame;
302         __u32 bcast = BROADCAST;
303         __u8 *info;
304 
305         IRDA_DEBUG(4, __FUNCTION__ "(), s=%d, S=%d, command=%d\n", s, S, 
306                    command);
307 
308         ASSERT(self != NULL, return;);
309         ASSERT(self->magic == LAP_MAGIC, return;);
310         ASSERT(discovery != NULL, return;);
311 
312         skb = dev_alloc_skb(64);
313         if (!skb)
314                 return;
315 
316         skb_put(skb, 14);
317         frame = (struct xid_frame *) skb->data;
318 
319         if (command) {
320                 frame->caddr = CBROADCAST | CMD_FRAME;
321                 frame->control =  XID_CMD | PF_BIT;
322         } else {
323                 frame->caddr = CBROADCAST;
324                 frame->control =  XID_RSP | PF_BIT;
325         }
326         frame->ident = XID_FORMAT;
327 
328         frame->saddr = cpu_to_le32(self->saddr);
329 
330         if (command)
331                 frame->daddr = cpu_to_le32(bcast);
332         else
333                 frame->daddr = cpu_to_le32(discovery->daddr);
334         
335         switch (S) {
336         case 1:
337                 frame->flags = 0x00;
338                 break;
339         case 6:
340                 frame->flags = 0x01;
341                 break;
342         case 8:
343                 frame->flags = 0x02;
344                 break;
345         case 16:
346                 frame->flags = 0x03;
347                 break;
348         default:
349                 frame->flags = 0x02;
350                 break;
351         }
352 
353         frame->slotnr = s; 
354         frame->version = 0x00;
355 
356         /*  
357          *  Provide info for final slot only in commands, and for all
358          *  responses. Send the second byte of the hint only if the
359          *  EXTENSION bit is set in the first byte.
360          */
361         if (!command || (frame->slotnr == 0xff)) {
362                 int len;
363 
364                 if (discovery->hints.byte[0] & HINT_EXTENSION) {
365                         info = skb_put(skb, 2);         
366                         info[0] = discovery->hints.byte[0];
367                         info[1] = discovery->hints.byte[1];
368                 } else {
369                         info = skb_put(skb, 1);
370                         info[0] = discovery->hints.byte[0];
371                 }
372                 info = skb_put(skb, 1);
373                 info[0] = discovery->charset;
374 
375                 len = IRDA_MIN(discovery->name_len, skb_tailroom(skb));
376                 info = skb_put(skb, len);
377                 memcpy(info, discovery->nickname, len);
378         } 
379         irlap_queue_xmit(self, skb);
380 }
381 
382 /*
383  * Function irlap_recv_discovery_xid_rsp (skb, info)
384  *
385  *    Received a XID discovery response
386  *
387  */
388 static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, 
389                                          struct sk_buff *skb, 
390                                          struct irlap_info *info) 
391 {
392         struct xid_frame *xid;
393         discovery_t *discovery = NULL;
394         __u8 *discovery_info;
395         char *text;
396 
397         IRDA_DEBUG(4, __FUNCTION__ "()\n");
398 
399         ASSERT(self != NULL, return;);
400         ASSERT(self->magic == LAP_MAGIC, return;);
401 
402         xid = (struct xid_frame *) skb->data;
403 
404         info->daddr = le32_to_cpu(xid->saddr);
405         info->saddr = le32_to_cpu(xid->daddr);
406 
407         /* Make sure frame is addressed to us */
408         if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
409                 IRDA_DEBUG(0, __FUNCTION__ 
410                            "(), frame is not addressed to us!\n");
411                 return;
412         }
413 
414         if ((discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
415                 WARNING(__FUNCTION__ "(), kmalloc failed!\n");
416                 return;
417         }
418         memset(discovery, 0, sizeof(discovery_t));
419 
420         discovery->daddr = info->daddr;
421         discovery->saddr = self->saddr;
422         discovery->timestamp = jiffies;
423 
424         IRDA_DEBUG(4, __FUNCTION__ "(), daddr=%08x\n", discovery->daddr);
425 
426         discovery_info = skb_pull(skb, sizeof(struct xid_frame));
427 
428         /* Get info returned from peer */
429         discovery->hints.byte[0] = discovery_info[0];
430         if (discovery_info[0] & HINT_EXTENSION) {
431                 IRDA_DEBUG(4, "EXTENSION\n");
432                 discovery->hints.byte[1] = discovery_info[1];
433                 discovery->charset = discovery_info[2];
434                 text = (char *) &discovery_info[3];
435         } else {
436                 discovery->hints.byte[1] = 0;
437                 discovery->charset = discovery_info[1];
438                 text = (char *) &discovery_info[2];
439         }
440         /* 
441          *  Terminate info string, should be safe since this is where the 
442          *  FCS bytes resides.
443          */
444         skb->data[skb->len] = '\0'; 
445         strncpy(discovery->nickname, text, NICKNAME_MAX_LEN);
446         discovery->name_len = strlen(discovery->nickname);
447 
448         info->discovery = discovery;
449 
450         irlap_do_event(self, RECV_DISCOVERY_XID_RSP, skb, info);
451 }
452 
453 /*
454  * Function irlap_recv_discovery_xid_cmd (skb, info)
455  *
456  *    Received a XID discovery command
457  *
458  */
459 static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, 
460                                          struct sk_buff *skb, 
461                                          struct irlap_info *info) 
462 {
463         struct xid_frame *xid;
464         discovery_t *discovery = NULL;
465         __u8 *discovery_info;
466         char *text;
467 
468         xid = (struct xid_frame *) skb->data;
469 
470         info->daddr = le32_to_cpu(xid->saddr);
471         info->saddr = le32_to_cpu(xid->daddr);
472 
473         /* Make sure frame is addressed to us */
474         if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
475                 IRDA_DEBUG(0, __FUNCTION__ 
476                            "(), frame is not addressed to us!\n");
477                 return;
478         }
479 
480         switch (xid->flags & 0x03) {
481         case 0x00:
482                 info->S = 1;
483                 break;
484         case 0x01:
485                 info->S = 6;
486                 break;
487         case 0x02:
488                 info->S = 8;
489                 break;
490         case 0x03:
491                 info->S = 16;
492                 break;
493         default:
494                 /* Error!! */
495                 dev_kfree_skb(skb);
496                 return;
497         }
498         info->s = xid->slotnr;
499         
500         discovery_info = skb_pull(skb, sizeof(struct xid_frame));
501 
502         /* 
503          *  Check if last frame 
504          */
505         if (info->s == 0xff) {
506                 /* Check if things are sane at this point... */
507                 if((discovery_info == NULL) || (skb->len < 3)) {
508                         ERROR(__FUNCTION__ "(), discovery frame to short!\n");
509                         return;
510                 }
511 
512                 /*
513                  *  We now have some discovery info to deliver!
514                  */
515                 discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC);
516                 if (!discovery) {
517                         WARNING(__FUNCTION__ "(), unable to malloc!\n");
518                         return;
519                 }
520               
521                 discovery->daddr = info->daddr;
522                 discovery->saddr = self->saddr;
523                 discovery->timestamp = jiffies;
524 
525                 discovery->hints.byte[0] = discovery_info[0];
526                 if (discovery_info[0] & HINT_EXTENSION) {
527                         discovery->hints.byte[1] = discovery_info[1];
528                         discovery->charset = discovery_info[2];
529                         text = (char *) &discovery_info[3];
530                 } else {
531                         discovery->hints.byte[1] = 0;
532                         discovery->charset = discovery_info[1];
533                         text = (char *) &discovery_info[2];
534                 }
535                 /* 
536                  *  Terminate string, should be safe since this is where the 
537                  *  FCS bytes resides.
538                  */
539                 skb->data[skb->len] = '\0'; 
540                 strncpy(discovery->nickname, text, NICKNAME_MAX_LEN);
541                 discovery->name_len = strlen(discovery->nickname);
542 
543                 info->discovery = discovery;
544         } else
545                 info->discovery = NULL;
546 
547         irlap_do_event(self, RECV_DISCOVERY_XID_CMD, skb, info);
548 }
549 
550 /*
551  * Function irlap_send_rr_frame (self, command)
552  *
553  *    Build and transmit RR (Receive Ready) frame. Notice that it is currently
554  *    only possible to send RR frames with the poll bit set.
555  */
556 void irlap_send_rr_frame(struct irlap_cb *self, int command) 
557 {
558         struct sk_buff *skb;
559         __u8 *frame;
560 
561         skb = dev_alloc_skb(16);
562         if (!skb)
563                 return;
564         
565         frame = skb_put(skb, 2);
566         
567         frame[0] = self->caddr;
568         frame[0] |= (command) ? CMD_FRAME : 0;
569 
570         frame[1] = RR | PF_BIT | (self->vr << 5);
571 
572         irlap_queue_xmit(self, skb);
573 }
574 
575 /*
576  * Function irlap_send_rd_frame (self)
577  *
578  *    Request disconnect. Used by a secondary station to request the 
579  *    disconnection of the link.
580  */
581 void irlap_send_rd_frame(struct irlap_cb *self)
582 {
583         struct sk_buff *skb;
584         __u8 *frame;
585 
586         skb = dev_alloc_skb(16);
587         if (!skb)
588                 return;
589         
590         frame = skb_put(skb, 2);
591         
592         frame[0] = self->caddr;
593         frame[1] = RD_RSP | PF_BIT;
594 
595         irlap_queue_xmit(self, skb);
596 }
597 
598 /*
599  * Function irlap_recv_rr_frame (skb, info)
600  *
601  *    Received RR (Receive Ready) frame from peer station, no harm in
602  *    making it inline since its called only from one single place
603  *    (irlap_driver_rcv).
604  */
605 static inline void irlap_recv_rr_frame(struct irlap_cb *self, 
606                                        struct sk_buff *skb, 
607                                        struct irlap_info *info, int command)
608 {
609         info->nr = skb->data[1] >> 5;
610 
611         /* Check if this is a command or a response frame */
612         if (command)
613                 irlap_do_event(self, RECV_RR_CMD, skb, info);
614         else
615                 irlap_do_event(self, RECV_RR_RSP, skb, info);
616 }
617 
618 void irlap_send_frmr_frame( struct irlap_cb *self, int command)
619 {
620         struct sk_buff *skb = NULL;
621         __u8 *frame;
622         
623         ASSERT( self != NULL, return;);
624         ASSERT( self->magic == LAP_MAGIC, return;);
625 
626         skb = dev_alloc_skb( 32);
627         if (!skb)
628                 return;
629 
630         frame = skb_put( skb, 2);
631         
632         frame[0] = self->caddr;
633         frame[0] |= (command) ? CMD_FRAME : 0;
634 
635         frame[1]  = (self->vs << 1);
636         frame[1] |= PF_BIT;
637         frame[1] |= (self->vr << 5);
638 
639         frame[2] = 0;
640 
641         IRDA_DEBUG(4, __FUNCTION__ "(), vr=%d, %ld\n",self->vr, jiffies); 
642 
643         irlap_queue_xmit(self, skb);
644 }
645 
646 /*
647  * Function irlap_recv_rnr_frame (self, skb, info)
648  *
649  *    Received RNR (Receive Not Ready) frame from peer station
650  *
651  */
652 static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, 
653                                  struct irlap_info *info, int command) 
654 {
655         info->nr = skb->data[1] >> 5;
656 
657         IRDA_DEBUG(4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
658 
659         if (command)
660                 irlap_do_event(self, RECV_RNR_CMD, skb, info);
661         else
662                 irlap_do_event(self, RECV_RNR_RSP, skb, info);
663 }
664 
665 static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, 
666                                  struct irlap_info *info, int command)
667 {
668         IRDA_DEBUG(0, __FUNCTION__ "()\n");
669 
670         info->nr = skb->data[1] >> 5;
671         
672         /* Check if this is a command or a response frame */
673         if (command)
674                 irlap_do_event(self, RECV_REJ_CMD, skb, info);
675         else
676                 irlap_do_event(self, RECV_REJ_RSP, skb, info);
677 }
678 
679 static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, 
680                                   struct irlap_info *info, int command)
681 {
682         IRDA_DEBUG(0, __FUNCTION__ "()\n");
683 
684         info->nr = skb->data[1] >> 5;
685         
686         /* Check if this is a command or a response frame */
687         if (command)
688                 irlap_do_event(self, RECV_SREJ_CMD, skb, info);
689         else
690                 irlap_do_event(self, RECV_SREJ_RSP, skb, info);
691 }
692 
693 static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, 
694                                   struct irlap_info *info, int command)
695 {
696         IRDA_DEBUG(0, __FUNCTION__ "()\n");
697 
698         /* Check if this is a command or a response frame */
699         if (command)
700                 irlap_do_event(self, RECV_DISC_CMD, skb, info);
701         else
702                 irlap_do_event(self, RECV_RD_RSP, skb, info);
703 }
704 
705 /*
706  * Function irlap_recv_ua_frame (skb, frame)
707  *
708  *    Received UA (Unnumbered Acknowledgement) frame
709  *
710  */
711 static inline void irlap_recv_ua_frame(struct irlap_cb *self, 
712                                        struct sk_buff *skb, 
713                                        struct irlap_info *info) 
714 {
715         irlap_do_event(self, RECV_UA_RSP, skb, info);
716 }
717 
718 /*
719  * Function irlap_send_data_primary(self, skb)
720  *
721  *    Send I-frames as the primary station but without the poll bit set
722  *
723  */
724 void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
725 {
726         struct sk_buff *tx_skb;
727 
728         if (skb->data[1] == I_FRAME) {
729 
730                 /*  
731                  *  Insert frame sequence number (Vs) in control field before
732                  *  inserting into transmit window queue.
733                  */
734                 skb->data[1] = I_FRAME | (self->vs << 1);
735                 
736                 /* Copy buffer */
737                 tx_skb = skb_clone(skb, GFP_ATOMIC);
738                 if (tx_skb == NULL) {
739                         return;
740                 }
741                 
742                 /*
743                  *  make sure the skb->sk accounting of memory usage is sane
744                  */
745                 if (skb->sk != NULL)
746                         skb_set_owner_w(tx_skb, skb->sk);
747                 
748                 /* 
749                  *  Insert frame in store, in case of retransmissions 
750                  */
751                 skb_queue_tail(&self->wx_list, skb_get(skb));
752                 
753                 self->vs = (self->vs + 1) % 8;
754                 self->ack_required = FALSE;             
755                 self->window -= 1;
756 
757                 irlap_send_i_frame( self, tx_skb, CMD_FRAME);
758         } else {
759                 IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
760                 irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
761                 self->window -= 1;
762         }
763 }
764 /*
765  * Function irlap_send_data_primary_poll (self, skb)
766  *
767  *    Send I(nformation) frame as primary with poll bit set
768  */
769 void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) 
770 {
771         struct sk_buff *tx_skb;
772 
773         /* Is this reliable or unreliable data? */
774         if (skb->data[1] == I_FRAME) {
775                 
776                 /*  
777                  *  Insert frame sequence number (Vs) in control field before
778                  *  inserting into transmit window queue.
779                  */
780                 skb->data[1] = I_FRAME | (self->vs << 1);
781                 
782                 /* Copy buffer */
783                 tx_skb = skb_clone(skb, GFP_ATOMIC);
784                 if (tx_skb == NULL) {
785                         return;
786                 }
787                 
788                 /*
789                  *  make sure the skb->sk accounting of memory usage is sane
790                  */
791                 if (skb->sk != NULL)
792                         skb_set_owner_w(tx_skb, skb->sk);
793                 
794                 /* 
795                  *  Insert frame in store, in case of retransmissions 
796                  */
797                 skb_queue_tail(&self->wx_list, skb_get(skb));
798                 
799                 /*  
800                  *  Set poll bit if necessary. We do this to the copied
801                  *  skb, since retransmitted need to set or clear the poll
802                  *  bit depending on when they are sent.  
803                  */
804                 /* Stop P timer */
805                 del_timer(&self->poll_timer);
806                 
807                 tx_skb->data[1] |= PF_BIT;
808                 
809                 self->vs = (self->vs + 1) % 8;
810                 self->ack_required = FALSE;
811                 self->window = self->window_size;
812 
813                 irlap_start_final_timer(self, self->final_timeout);
814 
815                 irlap_send_i_frame(self, tx_skb, CMD_FRAME);
816         } else {
817                 IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
818 
819                 del_timer(&self->poll_timer);
820 
821                 if (self->ack_required) {
822                         irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
823                         irlap_send_rr_frame(self, CMD_FRAME);
824                         self->ack_required = FALSE;
825                 } else {
826                         skb->data[1] |= PF_BIT;
827                         irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
828                 }
829                 self->window = self->window_size;
830                 irlap_start_final_timer(self, self->final_timeout);
831         }
832 }
833 
834 /*
835  * Function irlap_send_data_secondary_final (self, skb)
836  *
837  *    Send I(nformation) frame as secondary with final bit set
838  *
839  */
840 void irlap_send_data_secondary_final(struct irlap_cb *self, 
841                                      struct sk_buff *skb) 
842 {
843         struct sk_buff *tx_skb = NULL;
844 
845         ASSERT(self != NULL, return;);
846         ASSERT(self->magic == LAP_MAGIC, return;);
847         ASSERT(skb != NULL, return;);
848 
849         /* Is this reliable or unreliable data? */
850         if (skb->data[1] == I_FRAME) {
851 
852                 /*  
853                  *  Insert frame sequence number (Vs) in control field before
854                  *  inserting into transmit window queue.
855                  */
856                 skb->data[1] = I_FRAME | (self->vs << 1);
857                 
858                 tx_skb = skb_clone(skb, GFP_ATOMIC);
859                 if (tx_skb == NULL) {
860                         return;
861                 }               
862 
863                 if (skb->sk != NULL)
864                         skb_set_owner_w(tx_skb, skb->sk);
865                 
866                 /* Insert frame in store */
867                 skb_queue_tail(&self->wx_list, skb_get(skb));
868                 
869                 tx_skb->data[1] |= PF_BIT;
870                 
871                 self->vs = (self->vs + 1) % 8; 
872                 self->window = self->window_size;
873                 self->ack_required = FALSE;
874                 
875                 irlap_start_wd_timer(self, self->wd_timeout);
876 
877                 irlap_send_i_frame(self, tx_skb, RSP_FRAME); 
878         } else {
879                 if (self->ack_required) {
880                         irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
881                         irlap_send_rr_frame(self, RSP_FRAME);
882                         self->ack_required = FALSE;
883                 } else {
884                         skb->data[1] |= PF_BIT;
885                         irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
886                 }
887                 self->window = self->window_size;
888 
889                 irlap_start_wd_timer(self, self->wd_timeout);
890         }
891 }
892 
893 /*
894  * Function irlap_send_data_secondary (self, skb)
895  *
896  *    Send I(nformation) frame as secondary without final bit set
897  *
898  */
899 void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) 
900 {
901         struct sk_buff *tx_skb = NULL;
902 
903         /* Is this reliable or unreliable data? */
904         if (skb->data[1] == I_FRAME) {
905                 
906                 /*  
907                  *  Insert frame sequence number (Vs) in control field before
908                  *  inserting into transmit window queue.
909                  */
910                 skb->data[1] = I_FRAME | (self->vs << 1);
911                 
912                 tx_skb = skb_clone(skb, GFP_ATOMIC);
913                 if (tx_skb == NULL) {
914                         return;
915                 }               
916                 
917                 if (skb->sk != NULL)
918                         skb_set_owner_w(tx_skb, skb->sk);
919                 
920                 /* Insert frame in store */
921                 skb_queue_tail(&self->wx_list, skb_get(skb));
922                 
923                 self->vs = (self->vs + 1) % 8;
924                 self->ack_required = FALSE;             
925                 self->window -= 1;
926 
927                 irlap_send_i_frame(self, tx_skb, RSP_FRAME); 
928         } else {
929                 irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
930                 self->window -= 1;
931         }
932 }
933 
934 /*
935  * Function irlap_resend_rejected_frames (nr)
936  *
937  *    Resend frames which has not been acknowledged. Should be safe to 
938  *    traverse the list without locking it since this function will only be 
939  *    called from interrupt context (BH)
940  */
941 void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
942 {
943         struct sk_buff *tx_skb;
944         struct sk_buff *skb;
945         int count;
946 
947         ASSERT(self != NULL, return;);
948         ASSERT(self->magic == LAP_MAGIC, return;);
949 
950         /* Initialize variables */
951         skb = tx_skb = NULL;
952 
953         count = skb_queue_len(&self->wx_list);
954 
955         /*  Resend unacknowledged frame(s) */
956         skb = skb_peek(&self->wx_list);
957         while (skb != NULL) {
958                 irlap_wait_min_turn_around(self, &self->qos_tx);
959 
960                 /* We copy the skb to be retransmitted since we will have to 
961                  * modify it. Cloning will confuse packet sniffers 
962                  */
963                 /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
964                 tx_skb = skb_copy(skb, GFP_ATOMIC);
965                 if (!tx_skb) {
966                         IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
967                         return;
968                 }
969                 /* Unlink tx_skb from list */
970                 tx_skb->next = tx_skb->prev = NULL;
971                 tx_skb->list = NULL;
972 
973                 /*
974                  *  make sure the skb->sk accounting of memory usage is sane
975                  */
976                 if (skb->sk != NULL)
977                         skb_set_owner_w(tx_skb, skb->sk);
978 
979                 /* Clear old Nr field + poll bit */
980                 tx_skb->data[1] &= 0x0f;
981 
982                 /* 
983                  *  Set poll bit on the last frame retransmitted
984                  */
985                 if (count-- == 1)
986                         tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
987                 else
988                         tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */
989                 
990                 irlap_send_i_frame(self, tx_skb, command);
991 
992                 /* 
993                  *  If our skb is the last buffer in the list, then
994                  *  we are finished, if not, move to the next sk-buffer
995                  */
996                 if (skb == skb_peek_tail(&self->wx_list))
997                         skb = NULL;
998                 else
999                         skb = skb->next;
1000         }
1001 #if 0 /* Not yet */
1002         /* 
1003          *  We can now fill the window with additinal data frames
1004          */
1005         while (skb_queue_len( &self->txq) > 0) {
1006                 
1007                 IRDA_DEBUG(0, __FUNCTION__ "(), sending additional frames!\n");
1008                 if ((skb_queue_len( &self->txq) > 0) && 
1009                     (self->window > 0)) {
1010                         skb = skb_dequeue( &self->txq); 
1011                         ASSERT(skb != NULL, return;);
1012 
1013                         /*
1014                          *  If send window > 1 then send frame with pf 
1015                          *  bit cleared
1016                          */ 
1017                         if ((self->window > 1) && 
1018                             skb_queue_len(&self->txq) > 0) 
1019                         {
1020                                 irlap_send_data_primary(self, skb);
1021                         } else {
1022                                 irlap_send_data_primary_poll(self, skb);
1023                         }
1024                         kfree_skb(skb);
1025                 }
1026         }
1027 #endif
1028 }
1029 
1030 void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
1031 {
1032         struct sk_buff *tx_skb;
1033         struct sk_buff *skb;
1034 
1035         ASSERT(self != NULL, return;);
1036         ASSERT(self->magic == LAP_MAGIC, return;);
1037 
1038         /* Initialize variables */
1039         skb = tx_skb = NULL;
1040 
1041         /*  Resend unacknowledged frame(s) */
1042         skb = skb_peek(&self->wx_list);
1043         if (skb != NULL) {
1044                 irlap_wait_min_turn_around(self, &self->qos_tx);
1045 
1046                 /* We copy the skb to be retransmitted since we will have to 
1047                  * modify it. Cloning will confuse packet sniffers 
1048                  */
1049                 /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
1050                 tx_skb = skb_copy(skb, GFP_ATOMIC);
1051                 if (!tx_skb) {
1052                         IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
1053                         return; 
1054                 }
1055                 /* Unlink tx_skb from list */
1056                 tx_skb->next = tx_skb->prev = NULL;
1057                 tx_skb->list = NULL;
1058 
1059                 /*
1060                  *  make sure the skb->sk accounting of memory usage is sane
1061                  */
1062                 if (skb->sk != NULL)
1063                         skb_set_owner_w(tx_skb, skb->sk);
1064 
1065                 /* Clear old Nr field + poll bit */
1066                 tx_skb->data[1] &= 0x0f;
1067 
1068                 /*  Set poll/final bit */
1069                 tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
1070                 
1071                 irlap_send_i_frame(self, tx_skb, command);
1072         }
1073 }
1074 
1075 /*
1076  * Function irlap_send_ui_frame (self, skb, command)
1077  *
1078  *    Contruct and transmit an Unnumbered Information (UI) frame
1079  *
1080  */
1081 void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, 
1082                          __u8 caddr, int command)
1083 {
1084         IRDA_DEBUG(4, __FUNCTION__ "()\n");
1085         
1086         ASSERT(self != NULL, return;);
1087         ASSERT(self->magic == LAP_MAGIC, return;);
1088         ASSERT(skb != NULL, return;);
1089         
1090         /* Insert connection address */
1091         skb->data[0] = caddr | ((command) ? CMD_FRAME : 0);
1092 
1093         irlap_queue_xmit(self, skb);
1094 }
1095 
1096 /*
1097  * Function irlap_send_i_frame (skb)
1098  *
1099  *    Contruct and transmit Information (I) frame
1100  */
1101 void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, 
1102                         int command) 
1103 {
1104         /* Insert connection address */
1105         skb->data[0] = self->caddr;
1106         skb->data[0] |= (command) ? CMD_FRAME : 0;
1107         
1108         /* Insert next to receive (Vr) */
1109         skb->data[1] |= (self->vr << 5);  /* insert nr */
1110 
1111         irlap_queue_xmit(self, skb);
1112 }
1113 
1114 /*
1115  * Function irlap_recv_i_frame (skb, frame)
1116  *
1117  *    Receive and parse an I (Information) frame, no harm in making it inline
1118  *    since it's called only from one single place (irlap_driver_rcv).
1119  */
1120 static inline void irlap_recv_i_frame(struct irlap_cb *self, 
1121                                       struct sk_buff *skb, 
1122                                       struct irlap_info *info, int command) 
1123 {
1124         info->nr = skb->data[1] >> 5;          /* Next to receive */
1125         info->pf = skb->data[1] & PF_BIT;      /* Final bit */
1126         info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */
1127 
1128         /* Check if this is a command or a response frame */
1129         if (command)
1130                 irlap_do_event(self, RECV_I_CMD, skb, info);
1131         else
1132                 irlap_do_event(self, RECV_I_RSP, skb, info);
1133 }
1134 
1135 /*
1136  * Function irlap_recv_ui_frame (self, skb, info)
1137  *
1138  *    Receive and parse an Unnumbered Information (UI) frame
1139  *
1140  */
1141 static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, 
1142                                 struct irlap_info *info)
1143 {
1144         IRDA_DEBUG( 4, __FUNCTION__ "()\n");
1145 
1146         info->pf = skb->data[1] & PF_BIT;      /* Final bit */
1147 
1148         irlap_do_event(self, RECV_UI_FRAME, skb, info);
1149 }
1150 
1151 /*
1152  * Function irlap_recv_frmr_frame (skb, frame)
1153  *
1154  *    Received Frame Reject response.
1155  *
1156  */
1157 static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, 
1158                                   struct irlap_info *info) 
1159 {
1160         __u8 *frame;
1161         int w, x, y, z;
1162 
1163         IRDA_DEBUG(0, __FUNCTION__ "()\n");
1164         
1165         ASSERT(self != NULL, return;);
1166         ASSERT(self->magic == LAP_MAGIC, return;);
1167         ASSERT(skb != NULL, return;);
1168         ASSERT(info != NULL, return;);
1169         
1170         frame = skb->data;
1171 
1172         info->nr = frame[2] >> 5;          /* Next to receive */
1173         info->pf = frame[2] & PF_BIT;      /* Final bit */
1174         info->ns = (frame[2] >> 1) & 0x07; /* Next to send */
1175 
1176         w = frame[3] & 0x01;
1177         x = frame[3] & 0x02;
1178         y = frame[3] & 0x04;
1179         z = frame[3] & 0x08;
1180         
1181         if (w) {
1182                 IRDA_DEBUG(0, "Rejected control field is undefined or not "
1183                       "implemented.\n");
1184         } 
1185         if (x) {
1186                 IRDA_DEBUG(0, "Rejected control field was invalid because it "
1187                       "contained a non permitted I field.\n");
1188         }
1189         if (y) {
1190                 IRDA_DEBUG(0, "Received I field exceeded the maximum negotiated "
1191                       "for the existing connection or exceeded the maximum "
1192                       "this station supports if no connection exists.\n");
1193         }
1194         if (z) {
1195                 IRDA_DEBUG(0, "Rejected control field control field contained an "
1196                       "invalid Nr count.\n");
1197         }
1198         irlap_do_event(self, RECV_FRMR_RSP, skb, info);
1199 }
1200 
1201 /*
1202  * Function irlap_send_test_frame (self, daddr)
1203  *
1204  *    Send a test frame response
1205  *
1206  */
1207 void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, 
1208                            struct sk_buff *cmd)
1209 {
1210         struct sk_buff *skb;
1211         struct test_frame *frame;
1212         __u8 *info;
1213 
1214         skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame));
1215         if (!skb)
1216                 return;
1217 
1218         /* Broadcast frames must include saddr and daddr fields */
1219         if (caddr == CBROADCAST) {
1220                 frame = (struct test_frame *) 
1221                         skb_put(skb, sizeof(struct test_frame));
1222 
1223                 /* Insert the swapped addresses */
1224                 frame->saddr = cpu_to_le32(self->saddr);
1225                 frame->daddr = cpu_to_le32(daddr);
1226         } else
1227                 frame = (struct test_frame *) skb_put(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER);
1228 
1229         frame->caddr = caddr;
1230         frame->control = TEST_RSP | PF_BIT;
1231 
1232         /* Copy info */
1233         info = skb_put(skb, cmd->len);
1234         memcpy(info, cmd->data, cmd->len);
1235 
1236         /* Return to sender */
1237         irlap_wait_min_turn_around(self, &self->qos_tx);
1238         irlap_queue_xmit(self, skb);
1239 }
1240 
1241 /*
1242  * Function irlap_recv_test_frame (self, skb)
1243  *
1244  *    Receive a test frame
1245  *
1246  */
1247 static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, 
1248                                   struct irlap_info *info, int command)
1249 {
1250         struct test_frame *frame;
1251 
1252         IRDA_DEBUG(2, __FUNCTION__ "()\n");
1253         
1254         frame = (struct test_frame *) skb->data;
1255                 
1256         /* Broadcast frames must carry saddr and daddr fields */
1257         if (info->caddr == CBROADCAST) {
1258                 if (skb->len < sizeof(struct test_frame)) {
1259                         IRDA_DEBUG(0, __FUNCTION__ 
1260                                    "() test frame to short!\n");
1261                         return;
1262                 }
1263                 
1264                 /* Read and swap addresses */
1265                 info->daddr = le32_to_cpu(frame->saddr);
1266                 info->saddr = le32_to_cpu(frame->daddr);
1267 
1268                 /* Make sure frame is addressed to us */
1269                 if ((info->saddr != self->saddr) && 
1270                     (info->saddr != BROADCAST)) {
1271                         return;
1272                 }
1273         }
1274 
1275         if (command)
1276                 irlap_do_event(self, RECV_TEST_CMD, skb, info);
1277         else
1278                 irlap_do_event(self, RECV_TEST_RSP, skb, info);
1279 }
1280 
1281 /*
1282  * Function irlap_driver_rcv (skb, netdev, ptype)
1283  *
1284  *    Called when a frame is received. Dispatches the right receive function 
1285  *    for processing of the frame.
1286  *
1287  */
1288 int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, 
1289                      struct packet_type *ptype)
1290 {
1291         struct irlap_info info;
1292         struct irlap_cb *self;
1293         int command;
1294         __u8 control;
1295         
1296         /* FIXME: should we get our own field? */
1297         self = (struct irlap_cb *) dev->atalk_ptr;
1298 
1299         /* If the net device is down, then IrLAP is gone! */
1300         if (!self || self->magic != LAP_MAGIC) {
1301                 dev_kfree_skb(skb);
1302                 return -1;
1303         }
1304 
1305         /* Check if frame is large enough for parsing */
1306         if (skb->len < 2) {
1307                 ERROR(__FUNCTION__ "(), frame to short!\n");
1308                 dev_kfree_skb(skb);
1309                 return -1;
1310         }
1311         
1312         command    = skb->data[0] & CMD_FRAME;
1313         info.caddr = skb->data[0] & CBROADCAST;
1314         
1315         info.pf      = skb->data[1] &  PF_BIT;
1316         info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */
1317 
1318         control = info.control;
1319 
1320         /*  First we check if this frame has a valid connection address */
1321         if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) {
1322                 IRDA_DEBUG(0, __FUNCTION__ "(), wrong connection address!\n");
1323                 goto out;
1324         }
1325         /*  
1326          *  Optimize for the common case and check if the frame is an
1327          *  I(nformation) frame. Only I-frames have bit 0 set to 0
1328          */
1329         if (~control & 0x01) {
1330                 irlap_recv_i_frame(self, skb, &info, command);
1331                 goto out;
1332         }
1333         /*
1334          *  We now check is the frame is an S(upervisory) frame. Only 
1335          *  S-frames have bit 0 set to 1 and bit 1 set to 0
1336          */
1337         if (~control & 0x02) {
1338                 /* 
1339                  *  Received S(upervisory) frame, check which frame type it is
1340                  *  only the first nibble is of interest
1341                  */
1342                 switch (control & 0x0f) {
1343                 case RR:
1344                         irlap_recv_rr_frame(self, skb, &info, command);
1345                         break;
1346                 case RNR:
1347                         irlap_recv_rnr_frame(self, skb, &info, command);
1348                         break;
1349                 case REJ:
1350                         irlap_recv_rej_frame(self, skb, &info, command);
1351                         break;
1352                 case SREJ:
1353                         irlap_recv_srej_frame(self, skb, &info, command);
1354                         break;
1355                 default:
1356                         WARNING(__FUNCTION__ 
1357                                 "() Unknown S-frame %02x received!\n",
1358                                 info.control);
1359                         break;
1360                 }
1361                 goto out;
1362         }
1363         /* 
1364          *  This must be a C(ontrol) frame 
1365          */
1366         switch (control) {
1367         case XID_RSP:
1368                 irlap_recv_discovery_xid_rsp(self, skb, &info);
1369                 break;
1370         case XID_CMD:
1371                 irlap_recv_discovery_xid_cmd(self, skb, &info);
1372                 break;
1373         case SNRM_CMD:
1374                 irlap_recv_snrm_cmd(self, skb, &info);
1375                 break;
1376         case DM_RSP:
1377                 irlap_do_event(self, RECV_DM_RSP, skb, &info);
1378                 break;
1379         case DISC_CMD: /* And RD_RSP since they have the same value */
1380                 irlap_recv_disc_frame(self, skb, &info, command);
1381                 break;
1382         case TEST_CMD:
1383                 irlap_recv_test_frame(self, skb, &info, command);
1384                 break;
1385         case UA_RSP:
1386                 irlap_recv_ua_frame(self, skb, &info);
1387                 break;
1388         case FRMR_RSP:
1389                 irlap_recv_frmr_frame(self, skb, &info);
1390                 break;
1391         case UI_FRAME:
1392                 irlap_recv_ui_frame(self, skb, &info);
1393                 break;
1394         default:
1395                 WARNING(__FUNCTION__ "(), Unknown frame %02x received!\n", 
1396                         info.control);
1397                 break;
1398         }
1399 out:
1400         dev_kfree_skb(skb); 
1401         return 0;
1402 }
1403 

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

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.