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