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