patch-2.1.132 linux/net/irda/irlmp_frame.c

Next file: linux/net/irda/irmod.c
Previous file: linux/net/irda/irlmp_event.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.131/linux/net/irda/irlmp_frame.c linux/net/irda/irlmp_frame.c
@@ -0,0 +1,373 @@
+/*********************************************************************
+ *                
+ * Filename:      irlmp_frame.c
+ * Version:       0.1
+ * Description:   IrLMP frame implementation
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Tue Aug 19 02:09:59 1997
+ * Modified at:   Wed Dec  9 01:25:47 1998
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *
+ *     Neither Dag Brattli nor University of Tromsų admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irlap.h>
+#include <net/irda/irlmp.h>
+#include <net/irda/irlmp_frame.h>
+
+static struct lsap_cb *irlmp_find_lsap( struct lap_cb *self, __u8 dlsap, 
+					__u8 slsap, int status);
+
+inline void irlmp_send_data_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap,
+				 int expedited, struct sk_buff *skb)
+{
+	__u8 *frame;
+
+	DEBUG( 4, __FUNCTION__ "()\n");
+
+	ASSERT( self != NULL, return;);
+	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT( skb != NULL, return;);
+
+	frame = skb->data;
+
+	frame[0] = dlsap;
+	frame[1] = slsap;
+
+	if ( expedited) {
+		DEBUG( 4, __FUNCTION__ "(), sending expedited data\n");
+		irlap_data_request( self->irlap, skb, FALSE);
+	} else {
+		DEBUG( 4, __FUNCTION__ "(), sending reliable data\n");
+		irlap_data_request( self->irlap, skb, TRUE);	
+	}
+}
+
+/*
+ * Function irlmp_send_lcf_pdu (dlsap, slsap, opcode,skb)
+ *
+ *    Send Link Control Frame to IrLAP
+ */
+void irlmp_send_lcf_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap,
+			 __u8 opcode, struct sk_buff *skb) 
+{
+	__u8 *frame;
+	
+	DEBUG( 4, __FUNCTION__ "()\n");
+	
+	ASSERT( self != NULL, return;);
+	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT( skb != NULL, return;);
+	
+	frame = skb->data;
+	
+	frame[0] = dlsap | CONTROL_BIT;
+	frame[1] = slsap;
+
+	frame[2] = opcode;
+
+	if (opcode == DISCONNECT)
+		frame[3] = 0x01; /* Service user request */
+	else
+		frame[3] = 0x00; /* rsvd */
+
+	ASSERT( self->irlap != NULL, return;);
+	irlap_data_request( self->irlap, skb, TRUE);
+}
+
+/*
+ * Function irlmp_input (skb)
+ *
+ *    Used by IrLAP to pass received data frames to IrLMP layer
+ *
+ */
+void irlmp_link_data_indication( struct lap_cb *self, int reliable, 
+				 struct sk_buff *skb)
+{
+	__u8 *fp;
+	__u8  slsap_sel;   /* Source (this) LSAP address */
+	__u8  dlsap_sel;   /* Destination LSAP address */
+	struct lsap_cb *lsap;
+
+	
+	DEBUG( 4, "irlmp_link_data_indication()\n");
+	
+	ASSERT( self != NULL, return;);
+	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT( skb != NULL, return;);
+	ASSERT( skb->len > 2, return;);
+
+	fp = skb->data;
+
+	/*
+	 *  The next statements may be confusing, but we do this so that 
+	 *  destination LSAP of received frame is source LSAP in our view
+	 */
+	slsap_sel = fp[0] & ~CONTROL_BIT; 
+	dlsap_sel = fp[1];
+	
+	DEBUG( 4, "slsap_sel = %02x, dlsap_sel = %02x\n", slsap_sel, 
+	       dlsap_sel);
+	
+	/*
+	 *  Check if this is an incoming connection, since we must deal with
+	 *  it in a different way than other established connections.
+	 */
+	if (( fp[0] & CONTROL_BIT) && ( fp[2] == CONNECT_CMD)) {
+		DEBUG( 4,"Incoming connection, source LSAP=%d, dest LSAP=%d\n",
+		       slsap_sel, dlsap_sel);
+		lsap = irlmp_find_lsap( self, dlsap_sel, slsap_sel, 
+					CONNECT_CMD);
+	} else
+		lsap = irlmp_find_lsap( self, dlsap_sel, slsap_sel, 0);
+
+	if ( lsap == NULL) {
+		DEBUG( 0, "IrLMP, Sorry, no LSAP for received frame!\n");
+		DEBUG( 0, __FUNCTION__ 
+		       "(), slsap_sel = %02x, dlsap_sel = %02x\n", slsap_sel, 
+		       dlsap_sel);
+		if ( fp[0] & CONTROL_BIT) {
+			DEBUG( 0, __FUNCTION__ 
+			       "(), received control frame %02x\n", fp[2]);
+		} else {
+			DEBUG( 0, __FUNCTION__ 
+			       "(), received data frame\n");
+		}
+		dev_kfree_skb( skb);
+		return;
+	}
+
+	/* 
+	 *  Check if we received a control frame? 
+	 */
+	if ( fp[0] & CONTROL_BIT) {
+		/* DEBUG( 0, "irlmp_input: Got control frame\n"); */
+		switch( fp[2]) {
+		case CONNECT_CMD:
+			DEBUG( 4, "irlmp_input: CONNECT_CMD\n");
+			lsap->lap = self;
+			irlmp_do_lsap_event( lsap, LM_CONNECT_INDICATION, skb);
+			break;
+		case CONNECT_CNF:
+			irlmp_do_lsap_event( lsap, LM_CONNECT_CONFIRM, skb);
+			break;
+		case DISCONNECT:
+			DEBUG( 4, "irlmp_input: Disconnect indication!\n");
+			irlmp_do_lsap_event( lsap, LM_DISCONNECT_INDICATION, 
+					     skb);
+			break;
+		case ACCESSMODE_CMD:
+			DEBUG( 0, "Access mode cmd not implemented!\n");
+			break;
+		case ACCESSMODE_CNF:
+			DEBUG( 0, "Access mode cnf not implemented!\n");
+			break;
+		default:
+			DEBUG( 0, "irlmp_input: Unknown control frame %02x\n",
+			       fp[2]);
+			break;
+		}
+	} else if ( reliable == LAP_RELIABLE) {
+		/* Must be pure data */
+		irlmp_do_lsap_event( lsap, LM_DATA_INDICATION, skb);
+	} else if ( reliable == LAP_UNRELIABLE) {
+		irlmp_do_lsap_event( lsap, LM_UDATA_INDICATION, skb);
+	}
+}
+
+/*
+ * Function irlmp_link_disconnect_indication (reason, userdata)
+ *
+ *    IrLAP has disconnected 
+ *
+ */
+void irlmp_link_disconnect_indication( struct lap_cb *lap, 
+				       struct irlap_cb *irlap, 
+				       LAP_REASON reason, 
+				       struct sk_buff *userdata)
+{
+	DEBUG( 4, "irlmp_link_disconnect_indication()\n");
+
+	ASSERT( lap != NULL, return;);
+	ASSERT( lap->magic == LMP_LAP_MAGIC, return;);
+
+	lap->reason = reason;
+
+        /* FIXME: must do something with the userdata if any */
+
+	/*
+	 *  Inform station state machine
+	 */
+	irlmp_do_lap_event( lap, LM_LAP_DISCONNECT_INDICATION, NULL);
+}
+
+/*
+ * Function irlmp_link_connect_indication (qos)
+ *
+ *    Incoming LAP connection!
+ *
+ */
+void irlmp_link_connect_indication( struct lap_cb *self, struct qos_info *qos,
+				    struct sk_buff *skb) 
+{
+	DEBUG( 4, "irlmp_link_connect_indication()\n");
+
+	/* Copy QoS settings for this session */
+	self->qos = qos;
+
+	irlmp_do_lap_event( self, LM_LAP_CONNECT_INDICATION, skb);
+}
+
+/*
+ * Function irlmp_link_connect_confirm (qos)
+ *
+ *    LAP connection confirmed!
+ *
+ */
+void irlmp_link_connect_confirm( struct lap_cb *self, struct qos_info *qos, 
+				 struct sk_buff *userdata)
+{
+	DEBUG( 4, "irlmp_link_connect_confirm()\n");
+
+	ASSERT( self != NULL, return;);
+	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT( qos != NULL, return;);
+
+	/* Copy QoS settings for this session */
+	self->qos = qos;
+
+	irlmp_do_lap_event( self, LM_LAP_CONNECT_CONFIRM, NULL);
+}
+
+/*
+ * Function irlmp_link_discovery_confirm (self, log)
+ *
+ *    Called by IrLAP with a list of discoveries after the discovery
+ *    request has been carried out. A NULL log is received if IrLAP
+ *    was unable to carry out the discovery request
+ *
+ */
+void irlmp_link_discovery_confirm( struct lap_cb *self, hashbin_t *log)
+{
+	DEBUG( 4, "irlmp_link_connect_confirm()\n");
+
+	ASSERT( self != NULL, return;);
+	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
+
+	if ( self->cachelog)
+		hashbin_delete( self->cachelog, (FREE_FUNC) kfree);
+
+	self->cachelog = log;
+      
+	irlmp_do_lap_event( self, LM_LAP_DISCOVERY_CONFIRM, NULL);
+}
+
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+void irlmp_update_cache( struct lsap_cb *self)
+{
+	DEBUG( 4, __FUNCTION__ "()\n");
+
+	/* Update cache entry */
+	irlmp->cache.dlsap_sel = self->dlsap_sel;
+	irlmp->cache.slsap_sel = self->slsap_sel;
+	irlmp->cache.lsap = self;
+	irlmp->cache.valid = TRUE;
+}
+#endif
+
+/*
+ * Function irlmp_find_handle (dlsap, slsap)
+ *
+ *    Find handle assosiated with destination and source LSAP
+ *
+ */
+static struct lsap_cb *irlmp_find_lsap( struct lap_cb *self, __u8 dlsap_sel,
+					__u8 slsap_sel, int status) 
+{
+	struct lsap_cb *lsap;
+	hashbin_t *queue;
+	
+	DEBUG( 4, "irlmp_find_lsap: dlsap_sel=0x%02x, slsap_sel=0x%02x\n", 
+	       dlsap_sel, slsap_sel);
+	
+	ASSERT( self != NULL, return NULL;);
+	ASSERT( self->magic == LMP_LAP_MAGIC, return NULL;);
+
+	if ( status)
+		queue = irlmp->unconnected_lsaps;
+	else
+		queue = self->lsaps;
+
+	/* 
+	 *  Optimize for the common case. We assume that the last frame
+	 *  received is in the same connection as the last one, so check in
+	 *  cache first to avoid the linear search
+	 */
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+	ASSERT( irlmp != NULL, return NULL;);
+
+	if (( irlmp->cache.valid) && 
+	    ( irlmp->cache.slsap_sel == slsap_sel) && 
+	    ( irlmp->cache.dlsap_sel == dlsap_sel)) 
+	{
+		DEBUG( 4, __FUNCTION__ "(), Using cached LSAP\n");
+		return ( irlmp->cache.lsap);
+	}	
+#endif
+	lsap = ( struct lsap_cb *) hashbin_get_first( queue);
+	while ( lsap != NULL) {
+		/* 
+		 *  Check if source LSAP (in our view!) match, and if
+		 *  dest LSAP is equal to LM_ANY, which is the case
+		 *  for incomming connections 
+		 */
+		DEBUG( 4, "irlmp_find_lsap: "
+		       "LSAP: lsap->dlsap=%d, lsap->slsap=%d\n", 
+		       lsap->dlsap_sel, lsap->slsap_sel);
+		
+		if (( status == CONNECT_CMD) && 
+		    ( lsap->slsap_sel == slsap_sel) &&      
+		    ( lsap->dlsap_sel == LSAP_ANY)) 
+		{
+			DEBUG( 4,"Incoming connection: Setting dlsap_sel=%d\n",
+			       dlsap_sel);
+			lsap->dlsap_sel = dlsap_sel;
+			
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+			irlmp_update_cache( lsap);
+#endif
+			return lsap;
+		}
+		/*
+		 *  Check if source LSAP and dest LSAP selectors match.
+		 */
+		if (( lsap->slsap_sel == slsap_sel) && 
+		    ( lsap->dlsap_sel == dlsap_sel)) 
+		{
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+			irlmp_update_cache( lsap);
+#endif
+			return lsap;
+		}
+		lsap = ( struct lsap_cb *) hashbin_get_next( queue);
+	}
+
+	/* Sorry not found! */
+	return NULL;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov