1/********************************************************************* 2 * 3 * Filename: irlan_provider.c 4 * Version: 0.9 5 * Description: IrDA LAN Access Protocol Implementation 6 * Status: Experimental. 7 * Author: Dag Brattli <dagb@cs.uit.no> 8 * Created at: Sun Aug 31 20:14:37 1997 9 * Modified at: Sat Oct 30 12:52:10 1999 10 * Modified by: Dag Brattli <dagb@cs.uit.no> 11 * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> 12 * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> 13 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> 14 * 15 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 16 * All Rights Reserved. 17 * 18 * This program is free software; you can redistribute it and/or 19 * modify it under the terms of the GNU General Public License as 20 * published by the Free Software Foundation; either version 2 of 21 * the License, or (at your option) any later version. 22 * 23 * Neither Dag Brattli nor University of Tromsø admit liability nor 24 * provide warranty for any of this software. This material is 25 * provided "AS-IS" and at no charge. 26 * 27 ********************************************************************/ 28 29#include <linux/kernel.h> 30#include <linux/string.h> 31#include <linux/errno.h> 32#include <linux/netdevice.h> 33#include <linux/etherdevice.h> 34#include <linux/init.h> 35#include <linux/random.h> 36#include <linux/bitops.h> 37#include <linux/slab.h> 38 39#include <asm/byteorder.h> 40 41#include <net/irda/irda.h> 42#include <net/irda/irttp.h> 43#include <net/irda/irlmp.h> 44#include <net/irda/irias_object.h> 45#include <net/irda/iriap.h> 46#include <net/irda/timer.h> 47 48#include <net/irda/irlan_common.h> 49#include <net/irda/irlan_eth.h> 50#include <net/irda/irlan_event.h> 51#include <net/irda/irlan_provider.h> 52#include <net/irda/irlan_filter.h> 53#include <net/irda/irlan_client.h> 54 55static void irlan_provider_connect_indication(void *instance, void *sap, 56 struct qos_info *qos, 57 __u32 max_sdu_size, 58 __u8 max_header_size, 59 struct sk_buff *skb); 60 61/* 62 * Function irlan_provider_control_data_indication (handle, skb) 63 * 64 * This function gets the data that is received on the control channel 65 * 66 */ 67static int irlan_provider_data_indication(void *instance, void *sap, 68 struct sk_buff *skb) 69{ 70 struct irlan_cb *self; 71 __u8 code; 72 73 self = instance; 74 75 IRDA_ASSERT(self != NULL, return -1;); 76 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); 77 78 IRDA_ASSERT(skb != NULL, return -1;); 79 80 code = skb->data[0]; 81 switch(code) { 82 case CMD_GET_PROVIDER_INFO: 83 pr_debug("Got GET_PROVIDER_INFO command!\n"); 84 irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb); 85 break; 86 87 case CMD_GET_MEDIA_CHAR: 88 pr_debug("Got GET_MEDIA_CHAR command!\n"); 89 irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb); 90 break; 91 case CMD_OPEN_DATA_CHANNEL: 92 pr_debug("Got OPEN_DATA_CHANNEL command!\n"); 93 irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb); 94 break; 95 case CMD_FILTER_OPERATION: 96 pr_debug("Got FILTER_OPERATION command!\n"); 97 irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb); 98 break; 99 case CMD_RECONNECT_DATA_CHAN: 100 pr_debug("%s(), Got RECONNECT_DATA_CHAN command\n", __func__); 101 pr_debug("%s(), NOT IMPLEMENTED\n", __func__); 102 break; 103 case CMD_CLOSE_DATA_CHAN: 104 pr_debug("Got CLOSE_DATA_CHAN command!\n"); 105 pr_debug("%s(), NOT IMPLEMENTED\n", __func__); 106 break; 107 default: 108 pr_debug("%s(), Unknown command!\n", __func__); 109 break; 110 } 111 return 0; 112} 113 114/* 115 * Function irlan_provider_connect_indication (handle, skb, priv) 116 * 117 * Got connection from peer IrLAN client 118 * 119 */ 120static void irlan_provider_connect_indication(void *instance, void *sap, 121 struct qos_info *qos, 122 __u32 max_sdu_size, 123 __u8 max_header_size, 124 struct sk_buff *skb) 125{ 126 struct irlan_cb *self; 127 struct tsap_cb *tsap; 128 129 self = instance; 130 tsap = sap; 131 132 IRDA_ASSERT(self != NULL, return;); 133 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); 134 135 IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;); 136 IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;); 137 138 self->provider.max_sdu_size = max_sdu_size; 139 self->provider.max_header_size = max_header_size; 140 141 irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL); 142 143 /* 144 * If we are in peer mode, the client may not have got the discovery 145 * indication it needs to make progress. If the client is still in 146 * IDLE state, we must kick it. 147 */ 148 if ((self->provider.access_type == ACCESS_PEER) && 149 (self->client.state == IRLAN_IDLE)) 150 { 151 irlan_client_wakeup(self, self->saddr, self->daddr); 152 } 153} 154 155/* 156 * Function irlan_provider_connect_response (handle) 157 * 158 * Accept incoming connection 159 * 160 */ 161void irlan_provider_connect_response(struct irlan_cb *self, 162 struct tsap_cb *tsap) 163{ 164 IRDA_ASSERT(self != NULL, return;); 165 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); 166 167 /* Just accept */ 168 irttp_connect_response(tsap, IRLAN_MTU, NULL); 169} 170 171static void irlan_provider_disconnect_indication(void *instance, void *sap, 172 LM_REASON reason, 173 struct sk_buff *userdata) 174{ 175 struct irlan_cb *self; 176 struct tsap_cb *tsap; 177 178 pr_debug("%s(), reason=%d\n", __func__ , reason); 179 180 self = instance; 181 tsap = sap; 182 183 IRDA_ASSERT(self != NULL, return;); 184 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); 185 IRDA_ASSERT(tsap != NULL, return;); 186 IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); 187 188 IRDA_ASSERT(tsap == self->provider.tsap_ctrl, return;); 189 190 irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); 191} 192 193/* 194 * Function irlan_parse_open_data_cmd (self, skb) 195 * 196 * 197 * 198 */ 199int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb) 200{ 201 int ret; 202 203 ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb); 204 205 /* Open data channel */ 206 irlan_open_data_tsap(self); 207 208 return ret; 209} 210 211/* 212 * Function parse_command (skb) 213 * 214 * Extract all parameters from received buffer, then feed them to 215 * check_params for parsing 216 * 217 */ 218int irlan_provider_parse_command(struct irlan_cb *self, int cmd, 219 struct sk_buff *skb) 220{ 221 __u8 *frame; 222 __u8 *ptr; 223 int count; 224 __u16 val_len; 225 int i; 226 char *name; 227 char *value; 228 int ret = RSP_SUCCESS; 229 230 IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;); 231 232 pr_debug("%s(), skb->len=%d\n", __func__ , (int)skb->len); 233 234 IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;); 235 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;); 236 237 if (!skb) 238 return -RSP_PROTOCOL_ERROR; 239 240 frame = skb->data; 241 242 name = kmalloc(255, GFP_ATOMIC); 243 if (!name) 244 return -RSP_INSUFFICIENT_RESOURCES; 245 value = kmalloc(1016, GFP_ATOMIC); 246 if (!value) { 247 kfree(name); 248 return -RSP_INSUFFICIENT_RESOURCES; 249 } 250 251 /* How many parameters? */ 252 count = frame[1]; 253 254 pr_debug("Got %d parameters\n", count); 255 256 ptr = frame+2; 257 258 /* For all parameters */ 259 for (i=0; i<count;i++) { 260 ret = irlan_extract_param(ptr, name, value, &val_len); 261 if (ret < 0) { 262 pr_debug("%s(), IrLAN, Error!\n", __func__); 263 break; 264 } 265 ptr+=ret; 266 ret = RSP_SUCCESS; 267 irlan_check_command_param(self, name, value); 268 } 269 /* Cleanup */ 270 kfree(name); 271 kfree(value); 272 273 return ret; 274} 275 276/* 277 * Function irlan_provider_send_reply (self, info) 278 * 279 * Send reply to query to peer IrLAN layer 280 * 281 */ 282void irlan_provider_send_reply(struct irlan_cb *self, int command, 283 int ret_code) 284{ 285 struct sk_buff *skb; 286 287 IRDA_ASSERT(self != NULL, return;); 288 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); 289 290 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + 291 /* Bigger param length comes from CMD_GET_MEDIA_CHAR */ 292 IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") + 293 IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") + 294 IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") + 295 IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "HOSTED"), 296 GFP_ATOMIC); 297 298 if (!skb) 299 return; 300 301 /* Reserve space for TTP, LMP, and LAP header */ 302 skb_reserve(skb, self->provider.max_header_size); 303 skb_put(skb, 2); 304 305 switch (command) { 306 case CMD_GET_PROVIDER_INFO: 307 skb->data[0] = 0x00; /* Success */ 308 skb->data[1] = 0x02; /* 2 parameters */ 309 switch (self->media) { 310 case MEDIA_802_3: 311 irlan_insert_string_param(skb, "MEDIA", "802.3"); 312 break; 313 case MEDIA_802_5: 314 irlan_insert_string_param(skb, "MEDIA", "802.5"); 315 break; 316 default: 317 pr_debug("%s(), unknown media type!\n", __func__); 318 break; 319 } 320 irlan_insert_short_param(skb, "IRLAN_VER", 0x0101); 321 break; 322 323 case CMD_GET_MEDIA_CHAR: 324 skb->data[0] = 0x00; /* Success */ 325 skb->data[1] = 0x05; /* 5 parameters */ 326 irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); 327 irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST"); 328 irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST"); 329 330 switch (self->provider.access_type) { 331 case ACCESS_DIRECT: 332 irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT"); 333 break; 334 case ACCESS_PEER: 335 irlan_insert_string_param(skb, "ACCESS_TYPE", "PEER"); 336 break; 337 case ACCESS_HOSTED: 338 irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED"); 339 break; 340 default: 341 pr_debug("%s(), Unknown access type\n", __func__); 342 break; 343 } 344 irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee); 345 break; 346 case CMD_OPEN_DATA_CHANNEL: 347 skb->data[0] = 0x00; /* Success */ 348 if (self->provider.send_arb_val) { 349 skb->data[1] = 0x03; /* 3 parameters */ 350 irlan_insert_short_param(skb, "CON_ARB", 351 self->provider.send_arb_val); 352 } else 353 skb->data[1] = 0x02; /* 2 parameters */ 354 irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data); 355 irlan_insert_string_param(skb, "RECONNECT_KEY", "LINUX RULES!"); 356 break; 357 case CMD_FILTER_OPERATION: 358 irlan_filter_request(self, skb); 359 break; 360 default: 361 pr_debug("%s(), Unknown command!\n", __func__); 362 break; 363 } 364 365 irttp_data_request(self->provider.tsap_ctrl, skb); 366} 367 368/* 369 * Function irlan_provider_register(void) 370 * 371 * Register provider support so we can accept incoming connections. 372 * 373 */ 374int irlan_provider_open_ctrl_tsap(struct irlan_cb *self) 375{ 376 struct tsap_cb *tsap; 377 notify_t notify; 378 379 IRDA_ASSERT(self != NULL, return -1;); 380 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); 381 382 /* Check if already open */ 383 if (self->provider.tsap_ctrl) 384 return -1; 385 386 /* 387 * First register well known control TSAP 388 */ 389 irda_notify_init(¬ify); 390 notify.data_indication = irlan_provider_data_indication; 391 notify.connect_indication = irlan_provider_connect_indication; 392 notify.disconnect_indication = irlan_provider_disconnect_indication; 393 notify.instance = self; 394 strlcpy(notify.name, "IrLAN ctrl (p)", sizeof(notify.name)); 395 396 tsap = irttp_open_tsap(LSAP_ANY, 1, ¬ify); 397 if (!tsap) { 398 pr_debug("%s(), Got no tsap!\n", __func__); 399 return -1; 400 } 401 self->provider.tsap_ctrl = tsap; 402 403 /* Register with LM-IAS */ 404 irlan_ias_register(self, tsap->stsap_sel); 405 406 return 0; 407} 408 409