11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********************************************************************* 26819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Filename: ircomm_lmp.c 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version: 1.0 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Description: Interface between IrCOMM and IrLMP 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Status: Stable 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Dag Brattli <dagb@cs.uit.no> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created at: Sun Jun 6 20:48:27 1999 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified at: Sun Dec 12 13:44:17 1999 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified by: Dag Brattli <dagb@cs.uit.no> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sources: Previous IrLPT work by Thomas Davis 126819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1999 Dag Brattli, All Rights Reserved. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> 156819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * 166819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * This program is free software; you can redistribute it and/or 176819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * modify it under the terms of the GNU General Public License as 186819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * published by the Free Software Foundation; either version 2 of 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the License, or (at your option) any later version. 206819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 256819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * 266819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * You should have received a copy of the GNU General Public License 27d37705092fb1bad8dade186451f3cca754a5d1d1Jeff Kirsher * along with this program; if not, see <http://www.gnu.org/licenses/>. 286819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ********************************************************************/ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irda.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irlmp.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/iriap.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irda_device.h> /* struct irda_skb_cb */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/ircomm_event.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/ircomm_lmp.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function ircomm_lmp_connect_request (self, userdata) 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 466819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 496819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int ircomm_lmp_connect_request(struct ircomm_cb *self, 506819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki struct sk_buff *userdata, 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_info *info) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 550dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0, "%s()\n", __func__ ); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't forget to refcount it - should be NULL anyway */ 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(userdata) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_get(userdata); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = irlmp_connect_request(self->lsap, info->dlsap_sel, 626819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki info->saddr, info->daddr, NULL, userdata); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 646819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki} 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function ircomm_lmp_connect_response (self, skb) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 696819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ircomm_lmp_connect_response(struct ircomm_cb *self, 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *userdata) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *tx_skb; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 770dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0, "%s()\n", __func__ ); 786819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Any userdata supplied? */ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (userdata == NULL) { 811b0fee7d68f234be6b270cda51d9fcb71bebd780Samuel Ortiz tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tx_skb) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reserve space for MUX and LAP header */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(tx_skb, LMP_MAX_HEADER); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 886819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki /* 896819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * Check that the client has reserved enough space for 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * headers 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER, 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1;); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't forget to refcount it - should be NULL anyway */ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_get(userdata); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_skb = userdata; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1008ce6eb1a4a4bc46820f23e927377d386d3ec5404David S. Miller return irlmp_connect_response(self->lsap, tx_skb); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1036819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic int ircomm_lmp_disconnect_request(struct ircomm_cb *self, 1046819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki struct sk_buff *userdata, 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_info *info) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1076819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki struct sk_buff *tx_skb; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1100dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0, "%s()\n", __func__ ); 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1126819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki if (!userdata) { 1131b0fee7d68f234be6b270cda51d9fcb71bebd780Samuel Ortiz tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tx_skb) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1166819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reserve space for MUX and LAP header */ 1186819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki skb_reserve(tx_skb, LMP_MAX_HEADER); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds userdata = tx_skb; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't forget to refcount it - should be NULL anyway */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_get(userdata); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = irlmp_disconnect_request(self->lsap, userdata); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function ircomm_lmp_flow_control (skb) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is called when a data frame we have sent to IrLAP has 1346819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * been deallocated. We do this to make sure we don't flood IrLAP with 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * frames, since we are not using the IrTTP flow control mechanism 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ircomm_lmp_flow_control(struct sk_buff *skb) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irda_skb_cb *cb; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_cb *self; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int line; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(skb != NULL, return;); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb = (struct irda_skb_cb *) skb->cb; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1470dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(2, "%s()\n", __func__ ); 1486819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki 1496819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki line = cb->line; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL); 1526819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki if (!self) { 1530dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(2, "%s(), didn't find myself\n", __func__ ); 1546819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki return; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1576819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki IRDA_ASSERT(self != NULL, return;); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self->pkt_count--; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1626819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) { 1630dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __func__ ); 1646819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki self->flow_status = FLOW_START; 1656819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki if (self->notify.flow_indication) 1666819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki self->notify.flow_indication(self->notify.instance, 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self, FLOW_START); 1686819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki } 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1706819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function ircomm_lmp_data_request (self, userdata) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send data frame to peer device 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ircomm_lmp_data_request(struct ircomm_cb *self, 1786819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki struct sk_buff *skb, 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int not_used) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irda_skb_cb *cb; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(skb != NULL, return -1;); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cb = (struct irda_skb_cb *) skb->cb; 1876819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki 1886819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki cb->line = self->line; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1900dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(4, "%s(), sending frame\n", __func__ ); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't forget to refcount it - see ircomm_tty_do_softint() */ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_get(skb); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 195d55d87fdff8252d0e2f7c28c2d443aee17e9d70fHerbert Xu skb_orphan(skb); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->destructor = ircomm_lmp_flow_control; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1986819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) { 1990dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __func__ ); 2006819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki self->flow_status = FLOW_STOP; 2016819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki if (self->notify.flow_indication) 2026819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki self->notify.flow_indication(self->notify.instance, 2036819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki self, FLOW_STOP); 2046819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki } 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = irlmp_data_request(self->lsap, skb); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 2070dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_ERROR("%s(), failed\n", __func__); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* irlmp_data_request already free the packet */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function ircomm_lmp_data_indication (instance, sap, skb) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Incoming data which we must deliver to the state machine, to check 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we are still connected. 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ircomm_lmp_data_indication(void *instance, void *sap, 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_cb *self = (struct ircomm_cb *) instance; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2250dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(4, "%s()\n", __func__ ); 2266819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self != NULL, return -1;); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(skb != NULL, return -1;); 2306819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Drop reference count - see ircomm_tty_data_indication(). */ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2406819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki * Function ircomm_lmp_connect_confirm (instance, sap, qos, max_sdu_size, 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * max_header_size, skb) 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Connection has been confirmed by peer device 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ircomm_lmp_connect_confirm(void *instance, void *sap, 2476819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki struct qos_info *qos, 2486819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki __u32 max_seg_size, 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 max_header_size, 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb) 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_cb *self = (struct ircomm_cb *) instance; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_info info; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2550dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0, "%s()\n", __func__ ); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self != NULL, return;); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(skb != NULL, return;); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(qos != NULL, return;); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.max_data_size = max_seg_size; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.max_header_size = max_header_size; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.qos = qos; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Drop reference count - see ircomm_tty_connect_confirm(). */ 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function ircomm_lmp_connect_indication (instance, sap, qos, max_sdu_size, 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * max_header_size, skb) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Peer device wants to make a connection with us 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ircomm_lmp_connect_indication(void *instance, void *sap, 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qos_info *qos, 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u32 max_seg_size, 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 max_header_size, 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb) 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_cb *self = (struct ircomm_cb *)instance; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_info info; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2880dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0, "%s()\n", __func__ ); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self != NULL, return;); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(skb != NULL, return;); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(qos != NULL, return;); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.max_data_size = max_seg_size; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.max_header_size = max_header_size; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.qos = qos; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Drop reference count - see ircomm_tty_connect_indication(). */ 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function ircomm_lmp_disconnect_indication (instance, sap, reason, skb) 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Peer device has closed the connection, or the link went down for some 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * other reason 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3116819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideakistatic void ircomm_lmp_disconnect_indication(void *instance, void *sap, 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LM_REASON reason, 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_cb *self = (struct ircomm_cb *) instance; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ircomm_info info; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3180dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0, "%s()\n", __func__ ); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self != NULL, return;); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.reason = reason; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Drop reference count - see ircomm_tty_disconnect_indication(). */ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(skb) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function ircomm_open_lsap (self) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open LSAP. This function will only be used when using "raw" services 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ircomm_open_lsap(struct ircomm_cb *self) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds notify_t notify; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3410dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0, "%s()\n", __func__ ); 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Register callbacks */ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irda_notify_init(¬ify); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds notify.data_indication = ircomm_lmp_data_indication; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds notify.connect_confirm = ircomm_lmp_connect_confirm; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds notify.connect_indication = ircomm_lmp_connect_indication; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds notify.disconnect_indication = ircomm_lmp_disconnect_indication; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds notify.instance = self; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlcpy(notify.name, "IrCOMM", sizeof(notify.name)); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self->lsap = irlmp_open_lsap(LSAP_ANY, ¬ify, 0); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!self->lsap) { 3540dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __func__ ); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self->slsap_sel = self->lsap->slsap_sel; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialize the call-table for issuing commands 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self->issue.data_request = ircomm_lmp_data_request; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self->issue.connect_request = ircomm_lmp_connect_request; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self->issue.connect_response = ircomm_lmp_connect_response; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds self->issue.disconnect_request = ircomm_lmp_disconnect_request; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 369