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(&notify);
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, &notify, 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