patch-2.2.10 linux/net/irda/irlan/irlan_common.c

Next file: linux/net/irda/irlan/irlan_eth.c
Previous file: linux/net/irda/irlan/irlan_client_event.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.9/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 23:13:47 1999
+ * Modified at:   Mon May 31 14:25:19 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 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 
@@ -93,19 +94,25 @@
 static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, 
 				__u8 value_byte, __u16 value_short, 
 				__u8 *value_array, __u16 value_len);
-static void irlan_close_tsaps(struct irlan_cb *self);
+void irlan_close_tsaps(struct irlan_cb *self);
 
 #ifdef CONFIG_PROC_FS
 static int irlan_proc_read(char *buf, char **start, off_t offset, int len, 
 			   int unused);
 
 extern struct proc_dir_entry *proc_irda;
-#endif
+#endif /* CONFIG_PROC_FS */
 
+/*
+ * Function irlan_watchdog_timer_expired (data)
+ *
+ *    
+ *
+ */
 void irlan_watchdog_timer_expired(unsigned long data)
 {
 	struct irmanager_event mgr_event;
-	struct irlan_cb *self, *entry;
+	struct irlan_cb *self;
 	
 	DEBUG(0, __FUNCTION__ "()\n");
 
@@ -116,6 +123,7 @@
 
 	/* Check if device still configured */
 	if (self->dev.start) {
+		DEBUG(0, __FUNCTION__ "(), notifying irmanager to stop irlan!\n");
 		mgr_event.event = EVENT_IRLAN_STOP;
 		sprintf(mgr_event.devname, "%s", self->ifname);
 		irmanager_notify(&mgr_event);
@@ -128,22 +136,13 @@
 		 */
 		self->notify_irmanager = FALSE;
 	} else {
-		DEBUG(0, __FUNCTION__ "(), recycling instance!\n");
+		DEBUG(0, __FUNCTION__ "(), closing instance!\n");
 		if (self->netdev_registered) {
 			DEBUG(0, __FUNCTION__ "(), removing netdev!\n");
 			unregister_netdev(&self->dev);
 			self->netdev_registered = FALSE;
 		}
-
-		/* Unbind from daddr */
-		entry = hashbin_remove(irlan, self->daddr, NULL);
-		ASSERT(entry == self, return;);
-
-		self->daddr = DEV_ADDR_ANY;
-		self->saddr = DEV_ADDR_ANY;
-
-		DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
-		hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
+		irlan_close(self);
 	}
 }
 
@@ -195,12 +194,12 @@
 	/* Register with IrLMP as a service */
  	skey = irlmp_register_service(hints);
 
-	/* Start the first IrLAN instance */
+	/* Start the master IrLAN instance */
  	new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
 
-	irlan_open_data_tsap(new);
- 	irlan_client_open_ctrl_tsap(new);
+	/* The master will only open its (listen) control TSAP */
 	irlan_provider_open_ctrl_tsap(new);
+	new->master = TRUE;
 
 	/* Do some fast discovery! */
 	irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
@@ -293,7 +292,7 @@
 	self->daddr = daddr;
 
 	/* Provider access can only be PEER, DIRECT, or HOSTED */
-	self->access_type = access;
+	self->provider.access_type = access;
 	self->media = MEDIA_802_3;
 
 	self->notify_irmanager = TRUE;
@@ -302,7 +301,9 @@
 	init_timer(&self->client.kick_timer);
 
 	hashbin_insert(irlan, (QUEUE *) self, daddr, NULL);
-		
+	
+	skb_queue_head_init(&self->client.txq);
+	
 	irlan_next_client_state(self, IRLAN_IDLE);
 	irlan_next_provider_state(self, IRLAN_IDLE);
 
@@ -322,7 +323,7 @@
  */
 static void __irlan_close(struct irlan_cb *self)
 {
-	DEBUG(0, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -359,8 +360,11 @@
 
 	/* Check if device is still configured */
 	if (self->dev.start) {
-		DEBUG(2, __FUNCTION__ 
+		DEBUG(0, __FUNCTION__ 
 		       "(), Device still configured, closing later!\n");
+
+		/* Give it a chance to reconnect */
+		irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
 		return;
 	}
 	DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
@@ -371,8 +375,15 @@
         __irlan_close(self);
 }
 
+/*
+ * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb)
+ *
+ *    Here we receive the connect indication for the data channel
+ *
+ */
 void irlan_connect_indication(void *instance, void *sap, struct qos_info *qos,
-			      __u32 max_sdu_size, struct sk_buff *skb)
+			      __u32 max_sdu_size, __u8 max_header_size, 
+			      struct sk_buff *skb)
 {
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
@@ -386,13 +397,17 @@
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 	ASSERT(tsap == self->tsap_data,return;);
 
-	DEBUG(2, "IrLAN, We are now connected!\n");
+	self->max_sdu_size = max_sdu_size;
+	self->max_header_size = max_header_size;
+
+	DEBUG(0, "IrLAN, We are now connected!\n");
+
 	del_timer(&self->watchdog_timer);
 
 	irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, skb);
 	irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, skb);
 
-	if (self->access_type == ACCESS_PEER) {
+	if (self->provider.access_type == ACCESS_PEER) {
 		/* 
 		 * Data channel is open, so we are now allowed to
 		 * configure the remote filter 
@@ -400,22 +415,24 @@
 		irlan_get_unicast_addr(self);
 		irlan_open_unicast_addr(self);
 	}
-	/* Ready to transfer Ethernet frames */
+	/* Ready to transfer Ethernet frames (at last) */
 	self->dev.tbusy = 0;
 }
 
 void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-			   __u32 max_sdu_size, struct sk_buff *skb) 
+			   __u32 max_sdu_size, __u8 max_header_size, 
+			   struct sk_buff *skb) 
 {
 	struct irlan_cb *self;
 
-	DEBUG(2, __FUNCTION__ "()\n");
-
 	self = (struct irlan_cb *) instance;
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
+	self->max_sdu_size = max_sdu_size;
+	self->max_header_size = max_header_size;
+
 	/* TODO: we could set the MTU depending on the max_sdu_size */
 
 	DEBUG(2, "IrLAN, We are now connected!\n");
@@ -427,9 +444,15 @@
 	 */
 	irlan_get_unicast_addr(self);
 	irlan_open_unicast_addr(self);
+	
+	/* Open broadcast and multicast filter by default */
+ 	irlan_set_broadcast_filter(self, TRUE);
+ 	irlan_set_multicast_filter(self, TRUE);
 
 	/* Ready to transfer Ethernet frames */
 	self->dev.tbusy = 0;
+
+	irlan_eth_send_gratuitous_arp(&self->dev);
 }
 
 /*
@@ -444,7 +467,7 @@
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
 
-	DEBUG(2, __FUNCTION__ "(), reason=%d\n", reason);
+	DEBUG(0, __FUNCTION__ "(), reason=%d\n", reason);
 	
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -460,7 +483,7 @@
 
 	switch(reason) {
 	case LM_USER_REQUEST: /* User request */
-		//irlan_close(self);
+		irlan_close(self);
 		break;
 	case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
 		irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
@@ -478,9 +501,6 @@
 		break;
 	}
 	
-	/* Stop IP from transmitting more packets */
-	/* irlan_client_flow_indication(handle, FLOW_STOP, priv); */
-
 	irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
 	irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
 }
@@ -490,7 +510,7 @@
 	struct notify_t notify;
 	struct tsap_cb *tsap;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -500,12 +520,12 @@
 		return;
 
 	irda_notify_init(&notify);
-
+	
 	notify.data_indication       = irlan_eth_receive;
 	notify.udata_indication      = irlan_eth_receive;
 	notify.connect_indication    = irlan_connect_indication;
 	notify.connect_confirm       = irlan_connect_confirm;
- 	notify.flow_indication       = irlan_eth_flow_indication;
+ 	/*notify.flow_indication       = irlan_eth_flow_indication;*/
 	notify.disconnect_indication = irlan_disconnect_indication;
 	notify.instance              = self;
 	strncpy(notify.name, "IrLAN data", NOTIFY_MAX_NAME);
@@ -538,7 +558,6 @@
 		irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
 		irttp_close_tsap(self->tsap_data);
 		self->tsap_data = NULL;
-		
 	}
 	if (self->client.tsap_ctrl) {
 		irttp_disconnect_request(self->client.tsap_ctrl, NULL, 
@@ -591,15 +610,60 @@
 		irias_add_string_attrib(obj, "Name", "Linux");
 #endif
 		irias_add_string_attrib(obj, "DeviceID", "HWP19F0");
-		irias_add_integer_attrib(obj, "CompCnt", 2);
-		irias_add_string_attrib(obj, "Comp#01", "PNP8294");
-		irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+		irias_add_integer_attrib(obj, "CompCnt", 1);
+		if (self->provider.access_type == ACCESS_PEER)
+			irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+		else
+			irias_add_string_attrib(obj, "Comp#01", "PNP8294");
+
 		irias_add_string_attrib(obj, "Manufacturer", "Linux-IrDA Project");
 		irias_insert_object(obj);
 	}
 }
 
 /*
+ * Function irlan_run_ctrl_tx_queue (self)
+ *
+ *    Try to send the next command in the control transmit queue
+ *
+ */
+int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
+{
+	struct sk_buff *skb;
+
+	if (irda_lock(&self->client.tx_busy) == FALSE)
+		return -EBUSY;
+
+	skb = skb_dequeue(&self->client.txq);
+	if (!skb) {
+		self->client.tx_busy = FALSE;
+		return 0;
+	}
+	if (self->client.tsap_ctrl == NULL) {
+		self->client.tx_busy = FALSE;
+		dev_kfree_skb(skb);
+		return -1;
+	}
+
+	return irttp_data_request(self->client.tsap_ctrl, skb);
+}
+
+/*
+ * Function irlan_ctrl_data_request (self, skb)
+ *
+ *    This function makes sure that commands on the control channel is being
+ *    sent in a command/response fashion
+ */
+void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
+{
+	/* Queue command */
+	skb_queue_tail(&self->client.txq, skb);
+
+	/* Try to send command */
+	irlan_run_ctrl_tx_queue(self);
+}
+
+/*
  * Function irlan_get_provider_info (self)
  *
  *    Send Get Provider Information command to peer IrLAN layer
@@ -620,7 +684,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -628,7 +692,8 @@
  	frame[0] = CMD_GET_PROVIDER_INFO;
 	frame[1] = 0x00;                 /* Zero parameters */
 	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -651,7 +716,7 @@
 	if (!skb)
 		return;
 
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -666,7 +731,8 @@
 
 /* 	self->use_udata = TRUE; */
 
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
 }
 
 void irlan_close_data_channel(struct irlan_cb *self) 
@@ -679,11 +745,15 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
+	/* Check if the TSAP is still there */
+	if (self->client.tsap_ctrl == NULL)
+		return;
+
 	skb = dev_alloc_skb(64);
 	if (!skb)
 		return;
 
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -694,7 +764,8 @@
 
 	irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
 
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -719,7 +790,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -730,7 +801,8 @@
  	irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
  	irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); 
 	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -757,7 +829,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -770,8 +842,9 @@
 		irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); 
 	else
 		irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); 
-	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -796,7 +869,7 @@
 		return;
 	
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -809,8 +882,9 @@
 		irlan_insert_string_param(skb, "FILTER_MODE", "ALL"); 
 	else
 		irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); 
-	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -836,7 +910,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -847,7 +921,8 @@
  	irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
  	irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC"); 
 	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -871,7 +946,7 @@
 		return;
 
 	/* Reserve space for TTP, LMP, and LAP header */
-	skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+	skb_reserve(skb, self->client.max_header_size);
 	skb_put(skb, 2);
 	
 	frame = skb->data;
@@ -882,7 +957,8 @@
 	
 	irlan_insert_string_param(skb, "MEDIA", "802.3");
 	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
 }
 
 /*
@@ -1033,7 +1109,7 @@
 	
 	/* get parameter name */
 	memcpy(name, buf+n, name_len);
-	name[ name_len] = '\0';
+	name[name_len] = '\0';
 	n+=name_len;
 	
 	/*  
@@ -1051,7 +1127,7 @@
 
 	/* get parameter value */
 	memcpy(value, buf+n, val_len);
-	value[ val_len] = '\0';
+	value[val_len] = '\0';
 	n+=val_len;
 	
 	DEBUG(4, "Parameter: %s ", name); 
@@ -1085,31 +1161,35 @@
 	while (self != NULL) {
 		ASSERT(self->magic == IRLAN_MAGIC, return len;);
 		
-		len += sprintf(buf+len, "ifname: %s,\n",
-			       self->ifname);
-		len += sprintf(buf+len, "client state: %s, ",
-			       irlan_state[ self->client.state]);
-		len += sprintf(buf+len, "provider state: %s,\n",
-			       irlan_state[ self->provider.state]);
-		len += sprintf(buf+len, "saddr: %#08x, ",
-			       self->saddr);
-		len += sprintf(buf+len, "daddr: %#08x\n",
-			       self->daddr);
-		len += sprintf(buf+len, "version: %d.%d,\n",
-			       self->version[1], self->version[0]);
-		len += sprintf(buf+len, "access type: %s\n", 
-			       irlan_access[ self->access_type]);
-		len += sprintf(buf+len, "media: %s\n", 
-			       irlan_media[ self->media]);
-
-		len += sprintf(buf+len, "local filter:\n");
-		len += sprintf(buf+len, "remote filter: ");
-		len += irlan_print_filter(self->client.filter_type, buf+len);
-
-		len += sprintf(buf+len, "tx busy: %s\n", self->dev.tbusy ? 
-			       "TRUE" : "FALSE");
-
-		len += sprintf(buf+len, "\n");
+		/* Don't display the master server */
+		if (self->master == 0) {
+			len += sprintf(buf+len, "ifname: %s,\n",
+				       self->ifname);
+			len += sprintf(buf+len, "client state: %s, ",
+				       irlan_state[ self->client.state]);
+			len += sprintf(buf+len, "provider state: %s,\n",
+				       irlan_state[ self->provider.state]);
+			len += sprintf(buf+len, "saddr: %#08x, ",
+				       self->saddr);
+			len += sprintf(buf+len, "daddr: %#08x\n",
+				       self->daddr);
+			len += sprintf(buf+len, "version: %d.%d,\n",
+				       self->version[1], self->version[0]);
+			len += sprintf(buf+len, "access type: %s\n", 
+				       irlan_access[self->client.access_type]);
+			len += sprintf(buf+len, "media: %s\n", 
+				       irlan_media[self->media]);
+			
+			len += sprintf(buf+len, "local filter:\n");
+			len += sprintf(buf+len, "remote filter: ");
+			len += irlan_print_filter(self->client.filter_type, 
+						  buf+len);
+			
+			len += sprintf(buf+len, "tx busy: %s\n", 
+				       self->dev.tbusy ? "TRUE" : "FALSE");
+			
+			len += sprintf(buf+len, "\n");
+		}
 
 		self = (struct irlan_cb *) hashbin_get_next(irlan);
  	} 
@@ -1132,34 +1212,34 @@
 		printk(KERN_INFO "Success\n");
 		break;
 	case 1:
-		printk(KERN_WARNING "Insufficient resources\n");
+		WARNING("IrLAN: Insufficient resources\n");
 		break;
 	case 2:
-		printk(KERN_WARNING "Invalid command format\n");
+		WARNING("IrLAN: Invalid command format\n");
 		break;
 	case 3:
-		printk(KERN_WARNING "Command not supported\n");
+		WARNING("IrLAN: Command not supported\n");
 		break;
 	case 4:
-		printk(KERN_WARNING "Parameter not supported\n");
+		WARNING("IrLAN: Parameter not supported\n");
 		break;
 	case 5:
-		printk(KERN_WARNING "Value not supported\n");
+		WARNING("IrLAN: Value not supported\n");
 		break;
 	case 6:
-		printk(KERN_WARNING "Not open\n");
+		WARNING("IrLAN: Not open\n");
 		break;
 	case 7:
-		printk(KERN_WARNING "Authentication required\n");
+		WARNING("IrLAN: Authentication required\n");
 		break;
 	case 8:
-		printk(KERN_WARNING "Invalid password\n");
+		WARNING("IrLAN: Invalid password\n");
 		break;
 	case 9:
-		printk(KERN_WARNING "Protocol error\n");
+		WARNING("IrLAN: Protocol error\n");
 		break;
 	case 255:
-		printk(KERN_WARNING "Asynchronous status\n");
+		WARNING("IrLAN: Asynchronous status\n");
 		break;
 	}
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)