1/********************************************************************* 2 * 3 * Filename: ircomm_ttp.c 4 * Version: 1.0 5 * Description: Interface between IrCOMM and IrTTP 6 * Status: Stable 7 * Author: Dag Brattli <dagb@cs.uit.no> 8 * Created at: Sun Jun 6 20:48:27 1999 9 * Modified at: Mon Dec 13 11:35:13 1999 10 * Modified by: Dag Brattli <dagb@cs.uit.no> 11 * 12 * Copyright (c) 1999 Dag Brattli, All Rights Reserved. 13 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License as 17 * published by the Free Software Foundation; either version 2 of 18 * the License, or (at your option) any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * You should have received a copy of the GNU General Public License 26 * along with this program; if not, see <http://www.gnu.org/licenses/>. 27 * 28 ********************************************************************/ 29 30#include <linux/init.h> 31 32#include <net/irda/irda.h> 33#include <net/irda/irlmp.h> 34#include <net/irda/iriap.h> 35#include <net/irda/irttp.h> 36 37#include <net/irda/ircomm_event.h> 38#include <net/irda/ircomm_ttp.h> 39 40static int ircomm_ttp_data_indication(void *instance, void *sap, 41 struct sk_buff *skb); 42static void ircomm_ttp_connect_confirm(void *instance, void *sap, 43 struct qos_info *qos, 44 __u32 max_sdu_size, 45 __u8 max_header_size, 46 struct sk_buff *skb); 47static void ircomm_ttp_connect_indication(void *instance, void *sap, 48 struct qos_info *qos, 49 __u32 max_sdu_size, 50 __u8 max_header_size, 51 struct sk_buff *skb); 52static void ircomm_ttp_flow_indication(void *instance, void *sap, 53 LOCAL_FLOW cmd); 54static void ircomm_ttp_disconnect_indication(void *instance, void *sap, 55 LM_REASON reason, 56 struct sk_buff *skb); 57static int ircomm_ttp_data_request(struct ircomm_cb *self, 58 struct sk_buff *skb, 59 int clen); 60static int ircomm_ttp_connect_request(struct ircomm_cb *self, 61 struct sk_buff *userdata, 62 struct ircomm_info *info); 63static int ircomm_ttp_connect_response(struct ircomm_cb *self, 64 struct sk_buff *userdata); 65static int ircomm_ttp_disconnect_request(struct ircomm_cb *self, 66 struct sk_buff *userdata, 67 struct ircomm_info *info); 68 69/* 70 * Function ircomm_open_tsap (self) 71 * 72 * 73 * 74 */ 75int ircomm_open_tsap(struct ircomm_cb *self) 76{ 77 notify_t notify; 78 79 IRDA_DEBUG(4, "%s()\n", __func__ ); 80 81 /* Register callbacks */ 82 irda_notify_init(¬ify); 83 notify.data_indication = ircomm_ttp_data_indication; 84 notify.connect_confirm = ircomm_ttp_connect_confirm; 85 notify.connect_indication = ircomm_ttp_connect_indication; 86 notify.flow_indication = ircomm_ttp_flow_indication; 87 notify.disconnect_indication = ircomm_ttp_disconnect_indication; 88 notify.instance = self; 89 strlcpy(notify.name, "IrCOMM", sizeof(notify.name)); 90 91 self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, 92 ¬ify); 93 if (!self->tsap) { 94 IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __func__ ); 95 return -1; 96 } 97 self->slsap_sel = self->tsap->stsap_sel; 98 99 /* 100 * Initialize the call-table for issuing commands 101 */ 102 self->issue.data_request = ircomm_ttp_data_request; 103 self->issue.connect_request = ircomm_ttp_connect_request; 104 self->issue.connect_response = ircomm_ttp_connect_response; 105 self->issue.disconnect_request = ircomm_ttp_disconnect_request; 106 107 return 0; 108} 109 110/* 111 * Function ircomm_ttp_connect_request (self, userdata) 112 * 113 * 114 * 115 */ 116static int ircomm_ttp_connect_request(struct ircomm_cb *self, 117 struct sk_buff *userdata, 118 struct ircomm_info *info) 119{ 120 int ret = 0; 121 122 IRDA_DEBUG(4, "%s()\n", __func__ ); 123 124 /* Don't forget to refcount it - should be NULL anyway */ 125 if(userdata) 126 skb_get(userdata); 127 128 ret = irttp_connect_request(self->tsap, info->dlsap_sel, 129 info->saddr, info->daddr, NULL, 130 TTP_SAR_DISABLE, userdata); 131 132 return ret; 133} 134 135/* 136 * Function ircomm_ttp_connect_response (self, skb) 137 * 138 * 139 * 140 */ 141static int ircomm_ttp_connect_response(struct ircomm_cb *self, 142 struct sk_buff *userdata) 143{ 144 int ret; 145 146 IRDA_DEBUG(4, "%s()\n", __func__ ); 147 148 /* Don't forget to refcount it - should be NULL anyway */ 149 if(userdata) 150 skb_get(userdata); 151 152 ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata); 153 154 return ret; 155} 156 157/* 158 * Function ircomm_ttp_data_request (self, userdata) 159 * 160 * Send IrCOMM data to IrTTP layer. Currently we do not try to combine 161 * control data with pure data, so they will be sent as separate frames. 162 * Should not be a big problem though, since control frames are rare. But 163 * some of them are sent after connection establishment, so this can 164 * increase the latency a bit. 165 */ 166static int ircomm_ttp_data_request(struct ircomm_cb *self, 167 struct sk_buff *skb, 168 int clen) 169{ 170 int ret; 171 172 IRDA_ASSERT(skb != NULL, return -1;); 173 174 IRDA_DEBUG(2, "%s(), clen=%d\n", __func__ , clen); 175 176 /* 177 * Insert clen field, currently we either send data only, or control 178 * only frames, to make things easier and avoid queueing 179 */ 180 IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;); 181 182 /* Don't forget to refcount it - see ircomm_tty_do_softint() */ 183 skb_get(skb); 184 185 skb_push(skb, IRCOMM_HEADER_SIZE); 186 187 skb->data[0] = clen; 188 189 ret = irttp_data_request(self->tsap, skb); 190 if (ret) { 191 IRDA_ERROR("%s(), failed\n", __func__); 192 /* irttp_data_request already free the packet */ 193 } 194 195 return ret; 196} 197 198/* 199 * Function ircomm_ttp_data_indication (instance, sap, skb) 200 * 201 * Incoming data 202 * 203 */ 204static int ircomm_ttp_data_indication(void *instance, void *sap, 205 struct sk_buff *skb) 206{ 207 struct ircomm_cb *self = (struct ircomm_cb *) instance; 208 209 IRDA_DEBUG(4, "%s()\n", __func__ ); 210 211 IRDA_ASSERT(self != NULL, return -1;); 212 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); 213 IRDA_ASSERT(skb != NULL, return -1;); 214 215 ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL); 216 217 /* Drop reference count - see ircomm_tty_data_indication(). */ 218 dev_kfree_skb(skb); 219 220 return 0; 221} 222 223static void ircomm_ttp_connect_confirm(void *instance, void *sap, 224 struct qos_info *qos, 225 __u32 max_sdu_size, 226 __u8 max_header_size, 227 struct sk_buff *skb) 228{ 229 struct ircomm_cb *self = (struct ircomm_cb *) instance; 230 struct ircomm_info info; 231 232 IRDA_DEBUG(4, "%s()\n", __func__ ); 233 234 IRDA_ASSERT(self != NULL, return;); 235 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 236 IRDA_ASSERT(skb != NULL, return;); 237 IRDA_ASSERT(qos != NULL, goto out;); 238 239 if (max_sdu_size != TTP_SAR_DISABLE) { 240 IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n", 241 __func__); 242 goto out; 243 } 244 245 info.max_data_size = irttp_get_max_seg_size(self->tsap) 246 - IRCOMM_HEADER_SIZE; 247 info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE; 248 info.qos = qos; 249 250 ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info); 251 252out: 253 /* Drop reference count - see ircomm_tty_connect_confirm(). */ 254 dev_kfree_skb(skb); 255} 256 257/* 258 * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size, 259 * max_header_size, skb) 260 * 261 * 262 * 263 */ 264static void ircomm_ttp_connect_indication(void *instance, void *sap, 265 struct qos_info *qos, 266 __u32 max_sdu_size, 267 __u8 max_header_size, 268 struct sk_buff *skb) 269{ 270 struct ircomm_cb *self = (struct ircomm_cb *)instance; 271 struct ircomm_info info; 272 273 IRDA_DEBUG(4, "%s()\n", __func__ ); 274 275 IRDA_ASSERT(self != NULL, return;); 276 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 277 IRDA_ASSERT(skb != NULL, return;); 278 IRDA_ASSERT(qos != NULL, goto out;); 279 280 if (max_sdu_size != TTP_SAR_DISABLE) { 281 IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n", 282 __func__); 283 goto out; 284 } 285 286 info.max_data_size = irttp_get_max_seg_size(self->tsap) 287 - IRCOMM_HEADER_SIZE; 288 info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE; 289 info.qos = qos; 290 291 ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info); 292 293out: 294 /* Drop reference count - see ircomm_tty_connect_indication(). */ 295 dev_kfree_skb(skb); 296} 297 298/* 299 * Function ircomm_ttp_disconnect_request (self, userdata, info) 300 * 301 * 302 * 303 */ 304static int ircomm_ttp_disconnect_request(struct ircomm_cb *self, 305 struct sk_buff *userdata, 306 struct ircomm_info *info) 307{ 308 int ret; 309 310 /* Don't forget to refcount it - should be NULL anyway */ 311 if(userdata) 312 skb_get(userdata); 313 314 ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL); 315 316 return ret; 317} 318 319/* 320 * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb) 321 * 322 * 323 * 324 */ 325static void ircomm_ttp_disconnect_indication(void *instance, void *sap, 326 LM_REASON reason, 327 struct sk_buff *skb) 328{ 329 struct ircomm_cb *self = (struct ircomm_cb *) instance; 330 struct ircomm_info info; 331 332 IRDA_DEBUG(2, "%s()\n", __func__ ); 333 334 IRDA_ASSERT(self != NULL, return;); 335 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 336 337 info.reason = reason; 338 339 ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info); 340 341 /* Drop reference count - see ircomm_tty_disconnect_indication(). */ 342 if(skb) 343 dev_kfree_skb(skb); 344} 345 346/* 347 * Function ircomm_ttp_flow_indication (instance, sap, cmd) 348 * 349 * Layer below is telling us to start or stop the flow of data 350 * 351 */ 352static void ircomm_ttp_flow_indication(void *instance, void *sap, 353 LOCAL_FLOW cmd) 354{ 355 struct ircomm_cb *self = (struct ircomm_cb *) instance; 356 357 IRDA_DEBUG(4, "%s()\n", __func__ ); 358 359 IRDA_ASSERT(self != NULL, return;); 360 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 361 362 if (self->notify.flow_indication) 363 self->notify.flow_indication(self->notify.instance, self, cmd); 364} 365 366 367