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