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