The second try a committing the bluetooth code

Has been seen to work on several cards and communicating with
several mobile phones to use them as modems etc.

We are still talking with 3com to try get them to allow us to include
the firmware for their pccard in the driver but the driver is here..
In the mean time
it can be downloaded from the 3com website and loaded using the utility
bt3cfw(8) (supplied) (instructions in the man page)

Not yet linked to the build

Submitted by:	Maksim Yevmenkin <myevmenk@exodus.net>
Approved by:	re
This commit is contained in:
Julian Elischer 2002-11-20 23:01:59 +00:00
parent 2699228f1e
commit 878ed22696
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=107120
96 changed files with 34992 additions and 0 deletions

View File

@ -0,0 +1,109 @@
.\" ng_bluetooth.4
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: ng_bluetooth.4,v 1.2 2002/11/12 22:14:10 max Exp $
.\" $FreeBSD$
.Dd November 9, 2002
.Dt NG_BLUETOOTH 4
.Os
.Sh NAME
.Nm bluetooth
.Nd placeholder for global Bluetooth variables
.Sh SYNOPSIS
.In sys/types.h
.In ng_bluetooth.h
.Sh DESCRIPTION
The
.Nm
module is a placeholder for global Bluetooth variables. All Bluetooth
variables can be examined and changed via
.Xr sysctl 8 .
.Sh BLUETOOTH VARIABLES
Below is the description of default variables. Each Bluetooth module
might add its own variables to the tree.
.Bl -tag -width foobar
.It net.bluetooth.version
A read only integer variable that shows the current version of the
Bluetooth stack.
.It net.bluetooth.hci.command_timeout
A read-write interger variable that controls the Host Controller Interface
(HCI) command timeout (in seconds), i.e. how long the HCI layer will wait
for the
.Dv Command_Complete
or
.Dv Command_Status
event from a Bluetooth device.
.It net.bluetooth.hci.connection_timeout
A read-write integer variable that controls the HCI connection timeout, i.e.
how long the HCI layer will wait for the
.Dv Connection_Complete
event. Normaly this should not be required as Bluetooth devices have
connection timeout of their own and will send event back. This timeout
is required to ensure that no connection will stall in case when the HCI
transport layer is broken. Be careful when changing this variable.
Make sure you understand what you are doing.
.It net.bluetooth.hci.watchdog_timeout
A read-write integer variable that controls the HCI connection watchdog
timeout in seconds), i.e. how long the HCI layer should wait before
disconnecting an inactive baseband connection.
.Em This has not been implemented yet .
.It net.bluetooth.hci.max_neighbor_age
A read-write integer variable that controls time-to-live (in seconds) for
entries in the HCI neighbor cache. Every time a Bluetooth device performs
an
.Dv Inquiry
operation, the results will be put in cache. Later when a Bluetooth device
establishes a baseband connection, it will try to find the matching entry in
the cache and use it. This might speed up establishment of the baseband
connection.
.It net.bluetooth.l2cap.rtx_timeout
A read-write integer variable that controls the Link Layer Control and
Adaptation Protocol (L2CAP) Retransmission Timeout (RTX) (in seconds).
Every time the L2CAP layer submits a control command, the RTX timeout is set.
The value of the RTX timeout should be greater or equal to the value of
the HCI connection timeout. Be careful when changing this variable. Make
sure you understand what you are doing.
.It net.bluetooth.l2cap.ertx_timeout
A read-write integer variable that controls the L2CAP Extended Retransmission
Timeout (ERTX) (in seconds). In some cases remote peer may respond with
.Dv PENDING
status to the L2CAP control command. In this case the L2CAP command timeout
is reset to the ERTX timeout value. The value of the ERTX timeout should be
greater or equal to the value of the RTX timeout. Be careful when changing
this variable. Make sure you understand what you are doing.
.El
.Sh SEE ALSO
.Xr sysctl 8 ,
.Xr ng_hci 4 ,
.Xr ng_l2cap 4 ,
.Xr ng_btsocket 4
.Sh HISTORY
The
.Nm
module was implemented in
.Fx 5.0 .
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

136
share/man/man4/ng_bt3c.4 Normal file
View File

@ -0,0 +1,136 @@
.\" ng_bt3c.4
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: ng_bt3c.4,v 1.3 2002/11/12 17:03:58 max Exp $
.\" $FreeBSD$
.Dd June 14, 2002
.Dt NG_BT3C 4
.Os
.Sh NAME
.Nm BTCCC
.Nd Netgraph node type that is also a 3Com Bluetooth PC card driver
.Sh SYNOPSIS
.In sys/types.h
.In ng_bt3c.h
.Sh DESCRIPTION
The
.Nm BTCCC
node type is both a persistent Netgraph node type and a driver for
3Com Bluetooth PC card (3CRWB6096-HP). It implements a Bluetooth HCI
UART transport layer as per chapter H4 of the Bluetooth Specification
Book v1.1. A new node is created when the card is plugged.
.Pp
In order to use the card one
.Em MUST
download firmware first. Due to copyright issues I will no longer
provide firmware with the driver. The firmware can be obtained
from the Windows driver package that can be downloaded from the 3COM web
site at no charge. The firmware name is BT3CPCC.BIN. To load firmware
info the card use
.Xr bt3cfw 8 .
I'm using original firmware that came with the card on CD-ROM.
.Bd -literal -offset indent
MD5 (BT3CPCC.BIN) = 36170fda56ea9fdbf1702c966f8a97f1
.Ed
.Pp
For OLDCARD systems the entry in
.Xr pccard.conf 5
might look like this
.Bd -literal -offset indent
# 3Com 3CRWB60-A Bluetooth PC Card
card "3COM" "3CRWB60-A" "Bluetooth PC Card"
config auto "btccc" ?
insert /usr/sbin/bt3cfw -n $device -f /etc/BT3CPCC.bin
.Ed
.Pp
Do not forget to load module and SIGHUP
.Xr pccardd 8 .
.Pp
The node has a single hook called
.Dv hook .
Incoming bytes received on the device are re-assembled into HCI frames
(according to the length). Full HCI frames are sent out on the hook. HCI
frames received on
.Dv hook
are transmitted out. No modification to the data is performed in
either direction.
.Sh HOOKS
This node type supports the following hooks:
.Pp
.Bl -tag -width foobar
.It Dv hook
single HCI frame contained in single
.Dv mbuf
structure.
.El
.Sh CONTROL MESSAGES
This node type supports the generic control messages, plus the following:
.Bl -tag -width foo
.It Dv NGM_BT3C_NODE_GET_STATE
Returns current receiving state for the node.
.It Dv NGM_BT3C_NODE_GET_DEBUG
Returns an integer containing the current debug level for the node.
.It Dv NGM_BT3C_NODE_SET_DEBUG
This command takes an integer argument and sets current debug level
for the node.
.It Dv NGM_BT3C_NODE_GET_QLEN
This command takes a parameter that specifies queue number and returns
current length of the queue for the node.
.It Dv NGM_BT3C_NODE_SET_QLEN
This command takes two parameters that specify queue number and and
maximum length of the queue and sets maximum length of the queue for
the node.
.It Dv NGM_BT3C_NODE_GET_STAT
Returns various statistic information for the node, such as: number of
bytes (frames) sent, number of bytes (frames) received and number of
input (output) errors.
.It Dv NGM_BT3C_NODE_RESET_STAT
Reset all statistic counters to zero.
.It Dv NGM_BT3C_NODE_DOWNLOAD_FIRMWARE
Download card firmware.
.El
.Sh SHUTDOWN
This node shuts down when the corresponding card is un-plugged.
.Sh BUGS
The driver is based on information obrained from Jose Orlando Pereira
<jop@di.uminho.pt> and disassembled W2K driver.
.Sh SEE ALSO
.Xr cardbus 4 ,
.Xr pccbb 4 ,
.Xr pcic 4 ,
.Xr pccardc 8 ,
.Xr pccardd 8 ,
.Xr pccard.conf 5 ,
.Xr netgraph 4 ,
.Xr ngctl 8 ,
.Xr bt3cfw 8
.Sh HISTORY
The
.Nm BTCCC
node type was implemented in
.Fx 5.0 .
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View File

@ -0,0 +1,255 @@
.\" ng_btsocket.4
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: ng_btsocket.4,v 1.4 2002/11/12 22:31:39 max Exp $
.\" $FreeBSD$
.Dd July 8, 2002
.Dt NG_BTSOCKET 4
.Os
.Sh NAME
.Nm btsocket
.Nd Bluetooth sockets layer
.Sh SYNOPSIS
.In sys/types.h
.In sys/socket.h
.In bitstring.h
.In netgraph.h
.In ng_hci.h
.In ng_l2cap.h
.In ng_btsocket.h
.Sh DESCRIPTION
The
.Nm
module implements three Netgraph node types. Each type in its turn implements
one protocol within
.Dv PF_BLUETOOTH
domain.
.Pp
.Sh BLUETOOTH_PROTO_HCI protocol
.Ss SOCK_RAW HCI sockets
Implemented by
.Cm btsock_hci_raw
Netgraph type. Raw HCI sockets allow sending of raw HCI command datagrams
only to correspondents named in
.Xr send 2
calls. Raw HCI datagrams (HCI commands, events and data) are generally
received with
.Xr recvfrom 2 ,
which returns the next datagram with its return address. Also raw HCI
sockets can be used to control HCI nodes.
.Pp
The Bluetooth raw HCI socket address is defined as follows:
.Bd -literal -offset indent
/* Bluetooth version of struct sockaddr for raw HCI sockets */
struct sockaddr_hci {
u_char hci_len; /* total length */
u_char hci_family; /* address family */
char hci_node[16]; /* HCI node name */
};
.Ed
.Pp
Raw HCI sockets support number of
.Xr ioctl 2
requests such as:
.Bl -tag -width foo
.It Dv SIOC_HCI_RAW_NODE_GET_STATE
Returns current state for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_INIT
Turn on
.Dq inited
bit for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_GET_DEBUG
Returns current debug level for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_SET_DEBUG
Sets current debug level for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_GET_BUFFER
Returns current state of data buffers for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_GET_BDADDR
Returns BD_ADDR for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_GET_FEATURES
Returns the list of features supported by hardware for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_GET_STAT
Returns various statistic counters for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_RESET_STAT
Resets all statistic counters for the HCI node to zero.
.It Dv SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE
Remove all neighbor cache entries for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE
Returns content of the neighbor cache for the HCI node.
.It Dv SIOC_HCI_RAW_NODE_GET_CON_LIST
Returns list of active baseband connections (i.e. ACL and SCO links) for
the HCI node.
.It SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK
Returns current link policy settings mask for the HCI node.
.It SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK
Sets current link policy settings mask for the HCI node.
.It SIOC_HCI_RAW_NODE_GET_PACKET_MASK
Returns current packet mask for the HCI node.
.It SIOC_HCI_RAW_NODE_SET_PACKET_MASK
Sets current packet mask for the HCI node.
.El
.Pp
Raw HCI sockets support filters. The application can filter certain
HCI datagram types. For HCI event datagrams the application can set
additional filter. The raw HCI socket filter defined as follows:
.Bd -literal -offset indent
/*
* Raw HCI socket filter.
*
* For packet mask use (1 << (HCI packet indicator - 1))
* For event mask use (1 << (Event - 1))
*/
struct ng_btsocket_hci_raw_filter {
bitstr_t bit_decl(packet_mask, 32);
bitstr_t bit_decl(event_mask, (NG_HCI_EVENT_MASK_SIZE * 8));
};
.Ed
.Pp
The
.Dv SO_HCI_RAW_FILTER
option defined at
.Dv SOL_HCI_RAW
level can be used to obtain via
.Xr getsockopt 2
or change via
.Xr setsockopt 2
raw HCI socket's filter.
.Pp
.Sh BLUETOOTH_PROTO_L2CAP protocol
The Bluetooth L2CAP socket address is defined as follows:
.Bd -literal -offset indent
/* Bluetooth version of struct sockaddr for L2CAP sockets */
struct sockaddr_l2cap {
u_char l2cap_len; /* total length */
u_char l2cap_family; /* address family */
u_int16_t l2cap_psm; /* Protocol/Service Multiplexor */
bdaddr_t l2cap_bdaddr; /* address */
};
.Ed
.Pp
.Ss SOCK_RAW L2CAP sockets
Implemented by
.Cm btsock_l2c_raw
Netgraph type.
Raw L2CAP sockets do not provide access to raw L2CAP datagrams. These
sockets used to control L2CAP nodes and to issue special L2CAP requests
such as ECHO_REQUEST and GET_INFO request.
.Pp
Raw L2CAP sockets support number of
.Xr ioctl 2
requests such as:
.Bl -tag -width foo
.It Dv SIOC_L2CAP_NODE_GET_FLAGS
Returns current state for the L2CAP node.
.It Dv SIOC_L2CAP_NODE_GET_DEBUG
Returns current debug level for the L2CAP node.
.It Dv SIOC_L2CAP_NODE_SET_DEBUG
Sets current debug level for the L2CAP node.
.It Dv SIOC_L2CAP_NODE_GET_CON_LIST
Returns list of active baseband connections (i.e. ACL links) for the L2CAP
node.
.It Dv SIOC_L2CAP_NODE_GET_CHAN_LIST
Returns list of active channels for the L2CAP node.
.It Dv SIOC_L2CAP_L2CA_PING
Issues L2CAP ECHO_REQUEST.
.It Dv SIOC_L2CAP_L2CA_GET_INFO
Issues L2CAP GET_INFO request.
.El
.Pp
.Ss SOCK_SEQPACKET L2CAP sockets
Implemented by
.Cm btsock_l2c
Netgraph type.
L2CAP sockets are either
.Dq active
or
.Dq passive .
Active sockets initiate connections to passive sockets. By default L2CAP
sockets are created active; to create a passive socket the
.Xr listen 2
system call must be used after binding the socket with the
.Xr bind 2
system call. Only passive sockets may use the
.Xr accept 2
call to accept incoming connections. Only active sockets may use the
.Xr connect 2
call to initiate connections.
.Pp
L2CAP sockets supports
.Dq wildcard addressing .
In this case socket must be bound to
.Dv NG_HCI_BDADDR_ANY
address. Note that PSM (Protocol/Service Multiplexor) filed is always
required. Once a connection has been established the socket's address is
fixed by the peer entity's location. The address assigned the socket is
the address associated with the Bluetooth device through which packets are
being transmitted and received, and PSM (Protocol/Service Multiplexor).
.Pp
L2CAP sockets support number of options defined at
.Dv SOL_L2CAP
level which can be set with
.Xr setsockopt 2
and tested with
.Xr getsockopt 2 :
.Bl -tag -width foo
.It Dv SO_L2CAP_IMTU
Get (set) maximum payload size the local socket is capable of accepting.
.It Dv SO_L2CAP_OMTU
Get maximum payload size the remote socket is capable of accepting.
.It Dv SO_L2CAP_IFLOW
Get incoming flow specification for the socket.
.Em Not implemented .
.It Dv SO_L2CAP_OFLOW
Get (set) outgoing flow specification for the socket.
.Em Not implemented .
.It Dv SO_L2CAP_FLUSH
Get (set) value of the flush timeout.
.Em Not implemeted .
.El
.Sh HOOKS
This node type supports hooks with arbitrary names (as long as they are
unique) and always accepts hook connection requests.
.Sh NETGRAPH CONTROL MESSAGES
This node type supports the generic control messages.
.Sh SHUTDOWN
These nodes are persistent and cannot be shut down.
.Sh BUGS
Most likely. Please report if found.
.Sh SEE ALSO
.Xr socket 2 ,
.Xr netgraph 4 ,
.Xr ngctl 8 ,
.Xr ng_hci 4 ,
.Xr ng_l2cap 4 ,
.Xr btsockstat 1
.Sh HISTORY
The
.Nm
node type was implemented in
.Fx 5.0 .
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

121
share/man/man4/ng_h4.4 Normal file
View File

@ -0,0 +1,121 @@
.\" ng_h4.4
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: ng_h4.4,v 1.3 2002/11/12 17:10:13 max Exp $
.\" $FreeBSD$
.Dd June 14, 2002
.Dt NG_H4 4
.Os
.Sh NAME
.Nm h4
.Nd Netgraph node type that is also a H4 line discipline
.Sh SYNOPSIS
.In sys/types.h
.In sys/ttycom.h
.In netgraph/ng_message.h
.In netgraph/ng_h4.h
.Sh DESCRIPTION
The
.Nm
node type is both a persistent Netgraph node type and a H4 line
discipline. It implements a Bluetooth HCI UART transport layer as
per chapter H4 of the Bluetooth Specification Book v1.1. A new
node is created when the corresponding line discipline,
.Dv H4DISC ,
is registered on a tty device (see
.Xr tty 4 ) .
.Pp
The node has a single hook called
.Dv hook .
Incoming bytes received on the tty device are re-assembled into
HCI frames (according to the length). Full HCI frames are sent out on
the hook. HCI frames received on
.Dv hook
are transmitted out on the tty device.
No modification to the data is performed in either direction.
While the line discipline is installed on a tty, the normal
read and write operations are unavailable, returning
.Er EIO .
.Pp
Information about the node is available via the netgraph
.Xr ioctl 2
command
.Dv NGIOCGINFO .
This command returns a
.Dv "struct nodeinfo"
similar to the
.Dv NGM_NODEINFO
netgraph control message.
.Sh HOOKS
This node type supports the following hooks:
.Pp
.Bl -tag -width foobar
.It Dv hook
single HCI frame contained in single
.Dv mbuf
structure.
.El
.Sh CONTROL MESSAGES
This node type supports the generic control messages, plus the following:
.Bl -tag -width foo
.It Dv NGM_H4_NODE_RESET
Reset the node.
.It Dv NGM_H4_NODE_GET_STATE
Returns current receiving state for the node.
.It Dv NGM_H4_NODE_GET_DEBUG
Returns an integer containing the current debug level for the node.
.It Dv NGM_H4_NODE_SET_DEBUG
This command takes an integer argument and sets current debug level
for the node.
.It Dv NGM_H4_NODE_GET_QLEN
Returns current length of outgoing queue for the node.
.It Dv NGM_H4_NODE_SET_QLEN
This command takes an integer argument and sets maximum length of
outgoing queue for the node.
.It Dv NGM_H4_NODE_GET_STAT
Returns various statistic information for the node, such as: number of
bytes (frames) sent, number of bytes (frames) received and number of
input (output) errors.
.It Dv NGM_H4_NODE_RESET_STAT
Reset all statistic counters to zero.
.El
.Sh SHUTDOWN
This node shuts down when the corresponding device is closed
(or the line discipline is uninstalled on the device).
.Sh BUGS
This node still uses spltty() to lock tty layer. This is wrong.
.Sh SEE ALSO
.Xr ioctl 2 ,
.Xr netgraph 4 ,
.Xr tty 4 ,
.Xr ngctl 8
.Sh HISTORY
The
.Nm
node type was implemented in
.Fx 5.0 .
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

342
share/man/man4/ng_hci.4 Normal file
View File

@ -0,0 +1,342 @@
.\" ng_hci.4
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: ng_hci.4,v 1.8 2002/11/12 22:35:39 max Exp $
.\" $FreeBSD$
.Dd June 25, 2002
.Dt NG_HCI 4
.Os
.Sh NAME
.Nm hci
.Nd Netgraph node type that is also a Bluetooth Host Controller Interface
(HCI) layer
.Sh SYNOPSIS
.In sys/types.h
.In netgraph/ng_message.h
.In netgraph/netgraph.h
.In netgraph/ng_hci.h
.Sh DESCRIPTION
The
.Nm
node type is a Netgraph node type that implements Bluetooth Host Controller
Interface (HCI) layer as per chapter H1 of the Bluetooth Specification Book
v1.1.
.Sh INTRODUCTION TO BLUETOOTH
Bluetooth is a short-range radio link intended to replace the cable(s)
connecting portable and/or fixed electronic devices. Bluetooth operates
in the unlicensed ISM band at 2.4 GHz. The Bluetooth protocol uses a
combination of circuit and packet switching. Bluetooth can support an
asynchronous data channel, up to three simultaneous synchronous voice
channels, or a channel which simultaneously supports asynchronous data
and synchronous voice. Each voice channel supports a 64 kb/s synchronous
(voice) channel in each direction. The asynchronous channel can support
maximal 723.2 kb/s asymmetric (and still up to 57.6 kb/s in the return
direction), or 433.9 kb/s symmetric.
.Pp
The Bluetooth system provides a point-to-point connection (only two
Bluetooth units involved), or a point-to-multipoint connection. In the
point-to-multipoint connection, the channel is shared among several
Bluetooth units. Two or more units sharing the same channel form a
.Em piconet .
One Bluetooth unit acts as the master of the piconet, whereas the other
unit(s) acts as slave(s). Up to seven slaves can be active in the piconet.
In addition, many more slaves can remain locked to the master in a so-called
parked state. These parked slaves cannot be active on the channel, but remain
synchronized to the master. Both for active and parked slaves, the channel
access is controlled by the master.
.Pp
Multiple piconets with overlapping coverage areas form a
.Em scatternet .
Each piconet can only have a single master. However, slaves can participate
in different piconets on a time-division multiplex basis. In addition, a
master in one piconet can be a slave in another piconet. The piconets shall
not be frequency-synchronized. Each piconet has its own hopping channel.
.Ss Time slots
The channel is divided into time slots, each 625 usec in length. The time
slots are numbered according to the Bluetooth clock of the piconet master.
The slot numbering ranges from 0 to 2^27 -1 and is cyclic with a cycle length
of 2^27. In the time slots, master and slave can transmit packets.
.Ss SCO link
The SCO link is a symmetric, point-to-point link between the master and a
specific slave. The SCO link reserves slots and can therefore be considered
as a circuit-switched connection between the master and the slave. The SCO
link typically supports time-bounded information like voice. The master can
support up to three SCO links to the same slave or to different slaves. A
slave can support up to three SCO links from the same master, or two SCO
links if the links originate from different masters. SCO packets are never
retransmitted.
.Ss ACL link
In the slots not reserved for SCO links, the master can exchange packets
with any slave on a per-slot basis. The ACL link provides a packet-switched
connection between the master and all active slaves participating in the
piconet. Both asynchronous and isochronous services are supported. Between
a master and a slave only a single ACL link can exist. For most ACL packets,
packet retransmission is applied to assure data integrity.
.Sh HOST CONTROLLER INTERFACE (HCI)
The HCI provides a command interface to the baseband controller and link
manager, and access to hardware status and control registers. This interface
provides a uniform method of accessing the Bluetooth baseband capabilities.
.Pp
The HCI layer on the Host exchanges data and commands with the HCI firmware
on the Bluetooth hardware. The Host Controller Transport Layer (i.e. physical
bus) driver provides both HCI layers with the ability to exchange information
with each other.
.Pp
The Host will receive asynchronous notifications of HCI events independent
of which Host Controller Transport Layer is used. HCI events are used for
notifying the Host when something occurs. When the Host discovers that an
event has occurred it will then parse the received event packet to determine
which event occurred.
The next sections specify the HCI packet formats.
.Ss HCI command packet
.Bd -literal -offset indent
#define NG_HCI_CMD_PKT 0x01
typedef struct {
u_int8_t type; /* MUST be 0x1 */
u_int16_t opcode; /* OpCode */
u_int8_t length; /* parameter(s) length in bytes */
} __attribute__ ((packed)) ng_hci_cmd_pkt_t;
.Ed
.Pp
The HCI command packet is used to send commands to the Host Controller
from the Host. When the Host Controller completes most of the commands,
a Command Complete event is sent to the Host. Some commands do not receive
a Command Complete event when they have been completed. Instead, when the
Host Controller receives one of these commands the Host Controller sends
a Command Status event back to the Host when it has begun to execute the
command. Later on, when the actions associated with the command have finished,
an event that is associated with the sent command will be sent by the Host
Controller to the Host.
.Ss HCI event packet
.Bd -literal -offset indent
#define NG_HCI_EVENT_PKT 0x04
typedef struct {
u_int8_t type; /* MUST be 0x4 */
u_int8_t event; /* event */
u_int8_t length; /* parameter(s) length in bytes */
} __attribute__ ((packed)) ng_hci_event_pkt_t;
.Ed
.Pp
The HCI event packet is used by the Host Controller to notify the Host
when events occur.
.Ss HCI ACL data packet
.Bd -literal -offset indent
#define NG_HCI_ACL_DATA_PKT 0x02
typedef struct {
u_int8_t type; /* MUST be 0x2 */
u_int16_t con_handle; /* connection handle + PB + BC flags */
u_int16_t length; /* payload length in bytes */
} __attribute__ ((packed)) ng_hci_acldata_pkt_t;
.Ed
.Pp
HCI ACL data packets are used to exchange ACL data between the Host and
Host Controller.
.Ss HCI SCO data packet
.Bd -literal -offset indent
#define NG_HCI_SCO_DATA_PKT 0x03
typedef struct {
u_int8_t type; /* MUST be 0x3 */
u_int16_t con_handle; /* connection handle + reserved bits */
u_int8_t length; /* payload length in bytes */
} __attribute__ ((packed)) ng_hci_scodata_pkt_t;
.Ed
.Pp
HCI SCO data packets are used to exchange SCO data between the Host and
Host Controller.
.Sh HCI INITIALIZATION
On initialization, HCI control application must issue the following HCI
commands (in any order).
.Bl -tag -width foobar
.It Dv Read_BD_ADDR
To obtain BD_ADDR of the Bluetooth unit.
.It Dv Read_Local_Supported_Features
To obtain the list of features supported by Bluetooth unit.
.It Dv Read_Buffer_Size
To determine the maximum size of HCI ACL and SCO HCI data packets (excluding
header) that can be sent from the Host to the Host Controller. There are also
two additional return parameters that specify the total number of HCI ACL and
SCO data packets that the Host Controller can have waiting for transmission in
its buffers.
.El
.Pp
As soon as HCI initialization has been successfuly performed, HCI control
application must turn on
.Dq inited
bit for the node. Once HCI node has been initialized all upsteam hooks
will receive a
.Dv NGM_HCI_NODE_UP
Netgraph message defined as follows.
.Bd -literal -offset indent
#define NGM_HCI_NODE_UP 112 /* HCI -> Upper */
typedef struct {
u_int16_t pkt_size; /* max. ACL/SCO packet size (w/o hdr) */
u_int16_t num_pkts; /* ACL/SCO packet queue size */
u_int16_t reserved; /* place holder */
bdaddr_t bdaddr; /* bdaddr */
} ng_hci_node_up_ep;
.Ed
.Sh HCI FLOW CONTROL
HCI layer performs flow control on baseband connection basis (i.e. ACL and
SCO link). Each baseband connection has
.Em connection handle
and queue of outgoing data packets. Upper layers protocols are allowed to
send up to (
.Dv num_pkts -
.Dv pending )
packets at one time. HCI layer will send
.Dv NGM_HCI_SYNC_CON_QUEUE
Netgraph messages to inform upper layers about current queue state for each
connection handle. The
.Dv NGM_HCI_SYNC_CON_QUEUE
Netgraph message is defined as follows.
.Bd -literal -offset indent
#define NGM_HCI_SYNC_CON_QUEUE 113 /* HCI -> Upper */
typedef struct {
u_int16_t con_handle; /* connection handle */
u_int16_t completed; /* number of completed packets */
} ng_hci_sync_con_queue_ep;
.Ed
.Sh HOOKS
This node type supports the following hooks:
.Pp
.Bl -tag -width foobar
.It Dv drv
Bluetooth Host Controller Transport Layer hook. Single HCI packet contained in
single
.Dv mbuf
structure.
.It Dv acl
Upper layer protocol/node is connected to the hook. Single HCI ACL
data packet contained in single
.Dv mbuf
structure.
.It Dv sco
Upper layer protocol/node is connected to the hook. Single HCI SCO
data packet contained in single
.Dv mbuf
structure.
.It Dv raw
Raw hook. Every HCI frame (including HCI command frame) that goes in
or out will be delivired to the hook. Usually Bluetooth raw HCI sockets
layer is connected to the hook. Single HCI frame contained in single
. Dv mbuf
structure.
.El
.Sh BLUETOOTH UPPER LAYER PROTOCOLS INTERFACE (LP CONTROL MESSAGES)
.Bl -tag -width foo
.It Dv NGM_HCI_LP_CON_REQ
Requests the lower protocol to create a connection. If a physical link
to the remote device does not exist, this message must be sent to the lower
protocol (baseband) to establish the physical connection.
.It Dv NGM_HCI_LP_DISCON_REQ
Requests the lower protocol (baseband) to terminate a connection.
.It Dv NGM_HCI_LP_CON_CFM
Confirms success or failure of the
.Dv
NGM_HCI_LP_CON_REQ request to establish a lower layer (baseband) connection.
This includes passing the authentication challenge if authentication is
required to establish the physical link.
.It Dv NGM_HCI_LP_CON_IND
Indicates the lower protocol (baseband) has successfully established
incoming connection.
.It Dv NGM_HCI_LP_CON_RSP
A response accepting or rejecting the previous connection indication request.
.It Dv NGM_HCI_LP_DISCON_IND
Indicates the lower protocol (baseband) has terminated connection. This
could be a response to
.Dv NGM_HCI_LP_DISCON_REQ
or a timeout event.
.It Dv NGM_HCI_LP_QOS_REQ
Requests the lower protocol (baseband) to accommodate a particular QoS
parameter set.
.It Dv NGM_HCI_LP_QOS_CFM
Confirms success or failure of the request for a given quality of service.
.It Dv NGM_HCI_LP_QOS_IND
Indicates the lower protocol (baseband) has detected a violation of the QoS
agreement.
.El
.Sh NETGRAPH CONTROL MESSAGES
This node type supports the generic control messages, plus the following:
.Bl -tag -width foo
.It Dv NGM_HCI_NODE_GET_STATE
Returns current state for the node.
.It Dv NGM_HCI_NODE_INIT
Turn on
.Dq inited
bit for the node.
.It Dv NGM_HCI_NODE_GET_DEBUG
Returns an integer containing the current debug level for the node.
.It Dv NGM_HCI_NODE_SET_DEBUG
This command takes an integer argument and sets current debug level
for the node.
.It Dv NGM_HCI_NODE_GET_BUFFER
Returns current state of data buffers.
.It Dv NGM_HCI_NODE_GET_BDADDR
Returns BD_ADDR as cached in the node.
.It Dv NGM_HCI_NODE_GET_FEATURES
Returns the list of features supported by hardware (as cached by the node).
.It Dv NGM_HCI_NODE_GET_NEIGHBOR_CACHE
Returns content of the neighbor cache.
.It Dv NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE
Remove all neighbor cache entries.
.It Dv NGM_HCI_NODE_GET_CON_LIST
Returns list of active baseband connections (i.e. ACL and SCO links).
.It Dv NGM_HCI_NODE_GET_STAT
Returns various statistic counters.
.It Dv NGM_HCI_NODE_RESET_STAT
Resets all statistic counters to zero.
.It NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK
Sets current link policy settings mask. After the new ACL connection is
created the HCI node will try set link policy for the ACL connection. By
default every supported Link Manager (LM) mode will be enabled. User can
override this by setting link policy settings mask which specifies LM
modes to be enabled.
.It NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK
Returns current link policy settings mask.
.It NGM_HCI_NODE_SET_PACKET_MASK
Sets current packet mask. When new baseband (ACL or SCO) connection is
created the HCI node will specify every packet type supported by the device.
User can override this by setting packet mask which specifies packet types
to be used for new baseband connections.
.It NGM_HCI_NODE_GET_PACKET_MASK
Returns current packet mask.
.El
.Sh SHUTDOWN
This node shuts down upon receipt of a NGM_SHUTDOWN control message, or
when all hooks have been disconnected.
.Sh BUGS
Most likely. Please report if found.
.Sh SEE ALSO
.Xr netgraph 4 ,
.Xr ngctl 8 ,
.Xr hccontrol 8
.Sh HISTORY
The
.Nm
node type was implemented in
.Fx 5.0 .
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

341
share/man/man4/ng_l2cap.4 Normal file
View File

@ -0,0 +1,341 @@
.\" ng_l2cap.4
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: ng_l2cap.4,v 1.4 2002/11/12 17:16:19 max Exp $
.\" $FreeBSD$
.Dd July 4, 2002
.Dt NG_L2CAP 4
.Os
.Sh NAME
.Nm l2cap
.Nd Netgraph node type that implements Bluetooth Logical Link Control and
Adaptation Protocol (L2CAP)
.Sh SYNOPSIS
.In sys/types.h
.In netgraph/ng_message.h
.In netgraph/netgraph.h
.In netgraph/ng_hci.h
.In netgraph/ng_l2cap.h
.Sh DESCRIPTION
The
.Nm
node type is a Netgraph node type that implements Bluetooth Logical Link
Control and Adaptation Protocol as per chapter D of the Bluetooth Specification
Book v1.1.
.Pp
L2CAP provides connection-oriented and connectionless data services to upper
layer protocols with protocol multiplexing capability, segmentation and
reassembly operation, and group abstractions. L2CAP permits higher level
protocols and applications to transmit and receive L2CAP data packets up to
64 kilobytes in length.
.Ss L2CAP assumptions
.Bl -enum -offset indent
.It
The ACL link between two units is set up. The Baseband provides orderly
delivery of data packets, although there might be individual packet corruption
and duplicates. No more than 1 ACL link exists between any two devices.
.It
The Baseband always provides the impression of full-duplex communication
channels. This does not imply that all L2CAP communications are bi-directional.
Multicasts and unidirectional traffic (e.g., video) do not require duplex
channels.
.It
L2CAP provides a reliable channel using the mechanisms available at the
Baseband layer. The Baseband always performs data integrity checks when
requested and resends data until it has been successfully acknowledged or
a timeout occurs. Because acknowledgements may be lost, timeouts may
occur even after the data has been successfully sent.
.El
.Sh L2CAP GENERAL OPERATION
The Logical Link Control and Adaptation Protocol (L2CAP) is based around the
concept of
.Em channels .
Each channel is bound to a single protocol in a many-to-one fashion. Multiple
channels can be bound to the same protocol, but a channel cannot be bound to
multiple protocols. Each L2CAP packet received on a channel is directed to
the appropriate higher level protocol.
.Pp
Each one of the end-points of an L2CAP channel is referred to by a channel
identifier. Channel identifiers (CIDs) are local names representing a logical
channel end-point on the device. Identifiers from 0x0001 to 0x003F are reserved
for specific L2CAP functions. The null identifier (0x0000) is defined as an
illegal identifier and must never be used as a destination end-point.
All L2CAP signalling commands are sent to CID 0x0001. CID 0x0002 is reserved
for group-oriented channel. The same CID must not be reused as a local L2CAP
channel endpoint for multiple simultaneous L2CAP channels between a local
device and some remote device.
.Pp
CID assignment is relative to a particular device and a device can assign CIDs
independently from other devices. Thus, even if the same CID value has been
assigned to (remote) channel endpoints by several remote devices connected
to a single local device, the local device can still uniquely associate each
remote CID with a different device.
.Ss Channel operational states
.Bl -tag -width foobar
.It Dv NG_L2CAP_CLOSED
In this state, there is no channel associated with this CID. This is the only
state when a link level connection (Baseband) may not exist. Link disconnection
forces all other states into the NG_L2CAP_CLOSED state.
.It Dv NG_L2CAP_W4_L2CAP_CON_RSP
In this state, the CID represents a local end-point and an L2CAP Connect
Request message has been sent referencing this endpoint and it is now waiting
for the corresponding L2CAP Connect Response message.
.It Dv NG_L2CAP_W4_L2CA_CON_RSP
In this state, the remote end-point exists and an L2CAP Connect Request has
been received by the local L2CAP entity. An L2CA Connect Indication has been
sent to the upper layer and the part of the local L2CAP entity processing the
received L2CAP Connect Request waits for the corresponding response. The
response may require a security check to be performed.
.It Dv NG_L2CAP_CONFIG
In this state, the connection has been established but both sides are still
negotiating the channel parameters. The Configuration state may also be
entered when the channel parameters are being renegotiated. Prior to entering
the NG_L2CAP_CONFIG state, all outgoing data traffic is suspended since
the traffic parameters of the data traffic are to be renegotiated. Incoming
data traffic is accepted until the remote channel endpoint has entered
the NG_L2CAP_CONFIG state. In the NG_L2CAP_CONFIG state, both sides will issue
L2CAP Configuration Request messages if only defaults are being used, a null
message will be sent. If a large amount of parameters need to be negotiated,
multiple messages will be sent to avoid any MTU limitations and negotiate
incrementally. Moving from the NG_L2CAP_CONFIG state to the NG_L2CAP_OPEN state
requires both sides to be ready. An L2CAP entity is ready when it has received
a positive response to its final request and it has positively responded to
the final request from the remote device.
.It Dv NG_L2CAP_OPEN
In this state, the connection has been established and configured, and data
flow may proceed.
.It Dv NG_L2CAP_W4_L2CAP_DISCON_RSP
In this state, the connection is shutting down and an L2CAP Disconnect Request
message has been sent. This state is now waiting for the corresponding response.
.It Dv NG_L2CAP_W4_L2CA_DISCON_RSP
In this state, the connection on the remote endpoint is shutting down and an
L2CAP Disconnect Request message has been received. An L2CA Disconnect
Indication has been sent to the upper layer to notify the owner of the CID
that the remote endpoint is being closed. This state is now waiting for the
corresponding response from the upper layer before responding to the remote
endpoint.
.El
.Ss Protocol Multiplexing
L2CAP supports protocol multiplexing because the Baseband Protocol does not
support any
.Dq type
field identifying the higher layer protocol being multiplexed above it.
L2CAP is able to distinguish between upper layer protocols such as the Service
Discovery Protocol, RFCOMM and Telephony Control.
.Ss Segmentation and Reassembly
The data packets defined by the Baseband Protocol are limited in size. Large
L2CAP packets must be segmented into multiple smaller Baseband packets prior
to their transmission over the air. Similarly, multiple received Baseband
packets may be reassembled into a single larger L2CAP packet.
.Ss Quality of Service
The L2CAP connection establishment process allows the exchange of information
regarding the quality of service (QoS) expected between two Bluetooth units.
.Ss Groups
The Baseband Protocol supports the concept of a piconet, a group of devices
synchronously hopping together using the same clock. The L2CAP group
abstraction permits implementations to efficiently map protocol groups on to
piconets.
.Pp
The following features are outside the scope of L2CAP responsibilities:
.Bl -dash -offset indent
.It
L2CAP does not transport audio designated for SCO links.
.It
L2CAP does not enforce a reliable channel or ensure data integrity,
that is, L2CAP performs no retransmissions or checksum calculations.
.It
L2CAP does not support a reliable multicast channel.
.It
L2CAP does not support the concept of a global group name.
.El
.Sh HOOKS
This node type supports the following hooks:
.Pp
.Bl -tag -width foobar
.It Dv hci
Bluetooth Host Controller Interface downstream hook.
.It Dv l2c
Upper layer protocol upstream hook. Usually Bluetooth L2CAP sockets layer
is connected to the hook.
.It Dv ctl
Control hook. Usually Bluetooth raw L2CAP sockets layer is connected
to the hook.
.El
.Sh INTERFACE TO THE UPPER LAYER PROTOCOLS (L2CA CONTROL MESSAGES)
Bluetooth specification says that L2CA request must block until response
is ready. L2CAP node uses
.Dq token
field from Netgraph message header to match L2CA request and response. The
upper layer protocol must populate
.Dq token .
L2CAP node will queue request and start processing. Later, when response is
ready or timeout has occur L2CAP node will create new Netgraph message, set
.Dq token
and
.Dv NFG_RESP
flag and send message to the upper layer. Note that L2CA indication messages
will not populate
.Dq token
and will not set
.Dv NGF_RESP
flag. There is no reason for this, because they are just notifications and do
not require acknowledgment.
.Pp
.Bl -tag -width foo
.It Dv NGM_L2CAP_L2CA_CON
Requests the creation of a channel representing a logical connection to a
physical address. Input parameters are the target protocol (PSM) and remote
device's 48-bit address (BD_ADDR). Output parameters are the local CID (LCID)
allocated by the local L2CAP entity, and Result of the request. If Result
indicates a pending notification, the Status value may contain more information
of what processing is delaying the establishment of the connection.
.It Dv NGM_L2CAP_L2CA_CON_IND
This message includes the parameters for the address of the remote device that
issued the connection request, the local CID representing the channel being
requested, the Identifier contained in the request, and the PSM value the
request is targeting.
.It Dv NGM_L2CAP_L2CA_CON_RSP
Issues a response to a connection request event indication. Input parameters
are the remote device's 48-bit address, Identifier sent in the request, local
CID, the Response code, and the Status attached to the Response code. The
output parameter is the Result of the service request. This primitive must be
called no more than once after receiving the indication.
.It Dv NGM_L2CAP_L2CA_CFG
Requests the initial configuration (or reconfiguration) of a channel to a new
set of channel parameters. Input parameters are the local CID endpoint, new
incoming receivable MTU (InMTU), new outgoing flow spec-ification, and flush
and link timeouts. Output parameters are the Result, accepted incoming MTU
(InMTU), the remote side's flow requests, and flush and link timeouts.
.It Dv NGM_L2CAP_L2CA_CFG_IND
This message includes the parameters indicating the local CID of the channel
the request has been sent to, the outgoing MTU size (maximum packet that can
be sent across the channel) and the flowspec describing the characteristics of
the incoming data. All other channel parameters are set to their default values if not provided by the remote device.
.It Dv NGM_L2CAP_L2CA_CFG_RSP
Issues a response to a configuration request event indication. Input parameters
include the local CID of the endpoint being configured, outgoing transmit MTU
(which may be equal or less to the OutMTU parameter in the configuration
indication event) and the accepted flowspec for incoming traffic. The output
parameter is the Result value.
.It Dv NGM_L2CAP_L2CA_QOS_IND
This message includes the parameter indicating the address of the remote
Bluetooth device where the QoS contract has been violated.
.It Dv NGM_L2CAP_L2CA_DISCON
Requests the disconnection of the channel. Input parameter is the CID
representing the local channel endpoint. Output parameter is Result. Result
is zero if a L2CAP Disconnect Response is received, otherwise a non-zero value
is returned. Once disconnection has been requested, no process will be able to
successfully read or write from the CID.
.It Dv NGM_L2CAP_L2CA_DISCON_IND
This message includes the parameter indicating the local CID the request has
been sent to.
.It Dv NGM_L2CAP_L2CA_WRITE
Response to transfer of data request. Actual data must be received from
appropriate upstream hook and must be prepended with header defined as follows.
.Pp
.Bd -literal -offset indent
/* L2CA data packet header */
typedef struct {
u_int32_t token; /* token to use in L2CAP_L2CA_WRITE */
u_int16_t length; /* length of the data */
u_int16_t lcid; /* local channel ID */
} __attribute__ ((packed)) ng_l2cap_l2ca_hdr_t;
.Ed
.Pp
The output parameters are Result and Length of data written.
.It Dv NGM_L2CAP_L2CA_GRP_CREATE
Requests the creation of a CID to represent a logical connection to multiple
devices. Input parameter is the PSM value that the outgoing connectionless
traffic is labelled with, and the filter used for incoming traffic. Output
parameter is the CID representing the local endpoint. On creation, the group
is empty but incoming traffic destined for the PSM value is readable.
.Em This request has not been implemented .
.It Dv NGM_L2CAP_L2CA_GRP_CLOSE
The use of this message closes down a Group.
.Em This request has not been implemented .
.It Dv NGM_L2CAP_L2CA_GRP_ADD_MEMBER
Requests the addition of a member to a group. The input parameter includes the
CID representing the group and the BD_ADDR of the group member to be added.
The output parameter Result confirms the success or failure of the request.
.Em This request has not been implemented .
.It Dv NGM_L2CAP_L2CA_GRP_REM_MEMBER
Requests the removal of a member from a group. The input parameters include
the CID representing the group and BD_ADDR of the group member to be removed.
The output parameter Result confirms the success or failure of the request.
.Em This request has not been implemented .
.It Dv NGM_L2CAP_L2CA_GRP_MEMBERSHIP
Requests a report of the members of a group. The input parameter CID represents
the group being queried. The output parameter Result confirms the success or
failure of the operation. If the Result is successful, BD_ADDR_Lst is a list
of the Bluetooth addresses of the N members of the group.
.Em This request has not been implemented .
.It Dv NGM_L2CAP_L2CA_PING
Initiates a L2CA Echo Request message and the reception of the corresponding
L2CAP Echo Response message. The input parameters are remote Bluetooth device
BD_ADDR, Echo Data and Length of the echo data. The output parameters are
Result, Echo Data and Length of the echo data.
.It Dv NGM_L2CAP_L2CA_GET_INFO
Initiates a L2CA Information Request message and the reception of the
corresponding L2CAP Info Response message. The input parameters are remote
Bluetooth device BD_ADDR and Information Type. The output parameters are
Result, Information Data and Size of the information data.
.It Dv NGM_L2CAP_L2CA_ENABLE_CLT
Request to disable (enable) the reception of connectionless packets. The input
parameter is the PSM value indicating service that should be blocked
(unblocked) and Enable flag.
.El
.Sh NETGRAPH CONTROL MESSAGES
This node type supports the generic control messages, plus the following:
.Bl -tag -width foo
.It Dv NGM_L2CAP_NODE_GET_FLAGS
Returns current state for the node.
.It Dv NGM_L2CAP_NODE_GET_DEBUG
Returns an integer containing the current debug level for the node.
.It Dv NGM_L2CAP_NODE_SET_DEBUG
This command takes an integer argument and sets current debug level
for the node.
.It Dv NGM_L2CAP_NODE_GET_CON_LIST
Returns list of active baseband connections (i.e. ACL links).
.It Dv NGM_L2CAP_NODE_GET_CHAN_LIST
Returns list of active L2CAP channels.
.El
.Sh SHUTDOWN
This node shuts down upon receipt of a NGM_SHUTDOWN control message, or
when all hooks have been disconnected.
.Sh BUGS
Most likely. Please report if found.
.Sh SEE ALSO
.Xr netgraph 4 ,
.Xr ngctl 8 ,
.Xr l2control 8 ,
.Xr l2ping 8
.Sh HISTORY
The
.Nm
node type was implemented in
.Fx 5.0 .
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

102
share/man/man4/ng_ubt.4 Normal file
View File

@ -0,0 +1,102 @@
.\" ng_ubt.4
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: ng_ubt.4,v 1.2 2002/11/12 17:20:16 max Exp $
.\" $FreeBSD$
.Dd June 14, 2002
.Dt NG_UBT 4
.Os
.Sh NAME
.Nm ubt
.Nd Netgraph node type that is also a driver for Bluetooth USB devices
.Sh SYNOPSIS
.In sys/types.h
.In ng_ubt.h
.Sh DESCRIPTION
The
.Nm
node type is both a persistent Netgraph node type and a driver for
Bluetooth USB devices. It implements a Bluetooth USB transport layer
as per chapter H2 of the Bluetooth Specification Book v1.1. A new
node is created when supported USB device is plugged.
.Pp
The node has a single hook called
.Dv hook .
Incoming bytes received on the device are re-assembled into HCI frames
(according to the length). Full HCI frames are sent out on the hook. The node
will add HCI frame indicator if device did not send it. HCI frames received
on
.Dv hook
are transmitted out. The node will drop HCI frame indicator unless device
requires it to be present.
.Sh HOOKS
This node type supports the following hooks:
.Pp
.Bl -tag -width foobar
.It Dv hook
single HCI frame contained in single
.Dv mbuf
structure.
.El
.Sh CONTROL MESSAGES
This node type supports the generic control messages, plus the following:
.Bl -tag -width foo
.It Dv NGM_UBT_NODE_GET_DEBUG
Returns an integer containing the current debug level for the node.
.It Dv NGM_UBT_NODE_SET_DEBUG
This command takes an integer argument and sets current debug level
for the node.
.It Dv NGM_UBT_NODE_GET_QLEN
This command takes a parameter that specifies queue number and returns
current maximal length of the queue for the node.
.It Dv NGM_UBT_NODE_SET_QLEN
This command takes two parameters that specify queue number and maximum
length of the queue and sets maximal length of the queue for the node.
.It Dv NGM_UBT_NODE_GET_STAT
Returns various statistic information for the node, such as: number of
bytes (frames) sent, number of bytes (frames) received and number of
input (output) errors.
.It Dv NGM_UBT_NODE_RESET_STAT
Reset all statistic counters to zero.
.El
.Sh SHUTDOWN
This node shuts down when the corresponding USB device is un-plugged.
.Sh BUGS
Isochronous USB transfers are probably broken. It means that USB device
probably will not be able to transfer SCO data (voice). Driver does not
support firmware upgrade procedure. USB interrupt transfers are
implemented as bulk-in transfers (not really a bug).
.Sh SEE ALSO
.Xr usb 4 ,
.Xr netgraph 4 ,
.Xr ngctl 8
.Sh HISTORY
The
.Nm
node type was implemented in
.Fx 5.0 .
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View File

@ -0,0 +1,13 @@
# $FreeBSD$
SUBDIR= \
bluetooth \
hci \
l2cap \
socket \
bt3c \
h4 \
ubt
.include <bsd.subdir.mk>

View File

@ -0,0 +1,13 @@
# $Id: Makefile,v 1.1.1.1 2002/09/04 21:47:41 max Exp $
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../netgraph/bluetooth/common
CFLAGS+= -I../../../../netgraph/bluetooth/include
KMOD= ng_bluetooth
SRCS= ng_bluetooth.c
MAN4= ng_bluetooth.4
.include <bsd.kmod.mk>

View File

@ -0,0 +1,16 @@
# $Id: Makefile,v 1.6 2002/09/04 21:42:00 max Exp $
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../netgraph/bluetooth/drivers/bt3c
CFLAGS+= -g -I../../../../netgraph/bluetooth/include \
-I../../../../netgraph/bluetooth/drivers/bt3c \
-DINVARIANTS=1 -DINVARIANT_SUPPORT=1 \
-DWITNESS=1 -DWITNESS_SKIPSPIN=1
KMOD= ng_bt3c
SRCS= ng_bt3c_pccard.c bus_if.h card_if.h device_if.h
MAN4= ng_bt3c.4
.include <bsd.kmod.mk>

View File

@ -0,0 +1,16 @@
# $Id: Makefile,v 1.7 2002/11/03 02:15:54 max Exp $
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../netgraph/bluetooth/drivers/h4
CFLAGS+= -g -I../../../../netgraph/bluetooth/include \
-I../../../../netgraph/bluetooth/drivers/h4 \
-DINVARIANTS=1 -DINVARIANT_SUPPORT=1
# -DWITNESS=1 -DWITNESS_SKIPSPIN=1
KMOD= ng_h4
SRCS= ng_h4.c
MAN4= ng_h4.4
.include <bsd.kmod.mk>

View File

@ -0,0 +1,16 @@
# $Id: Makefile,v 1.5 2002/09/04 21:36:51 max Exp $
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../netgraph/bluetooth/hci
CFLAGS+= -g -I../../../../netgraph/bluetooth/include \
-I../../../../netgraph/bluetooth/hci \
-DINVARIANTS=1 -DINVARIANT_SUPPORT=1 \
-DWITNESS=1 -DWITNESS_SKIPSPIN=1
KMOD= ng_hci
SRCS= ng_hci_main.c ng_hci_cmds.c ng_hci_evnt.c \
ng_hci_ulpi.c ng_hci_misc.c
MAN4= ng_hci.4
.include <bsd.kmod.mk>

View File

@ -0,0 +1,16 @@
# $Id: Makefile,v 1.4 2002/09/04 21:38:38 max Exp $
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../netgraph/bluetooth/l2cap
CFLAGS+= -g -I../../../../netgraph/bluetooth/include \
-I../../../../netgraph/bluetooth/l2cap \
-DINVARIANTS=1 -DINVARIANT_SUPPORT=1 \
-DWITNESS=1 -DWITNESS_SKIPSPIN=1
KMOD= ng_l2cap
SRCS= ng_l2cap_main.c ng_l2cap_cmds.c ng_l2cap_evnt.c \
ng_l2cap_ulpi.c ng_l2cap_llpi.c ng_l2cap_misc.c
MAN4= ng_l2cap.4
.include <bsd.kmod.mk>

View File

@ -0,0 +1,17 @@
# $Id: Makefile,v 1.7 2002/09/04 21:43:59 max Exp $
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../netgraph/bluetooth/socket
CFLAGS+= -g -I../../../../netgraph/bluetooth/include \
-DINVARIANTS=1 -DINVARIANT_SUPPORT=1 \
-DWITNESS=1 -DWITNESS_SKIPSPIN=1
KMOD= ng_btsocket
SRCS= ng_btsocket.c \
ng_btsocket_hci_raw.c \
ng_btsocket_l2cap_raw.c \
ng_btsocket_l2cap.c
MAN4= ng_btsocket.4
.include <bsd.kmod.mk>

View File

@ -0,0 +1,16 @@
# $Id: Makefile,v 1.5 2002/09/04 21:41:06 max Exp $
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../netgraph/bluetooth/drivers/ubt
CFLAGS+= -g -I../../../../netgraph/bluetooth/include \
-I../../../../netgraph/bluetooth/drivers/ubt \
-DINVARIANTS=1 -DINVARIANT_SUPPORT=1 \
-DWITNESS=1 -DWITNESS_SKIPSPIN=1
KMOD= ng_ubt
SRCS= ng_ubt.c bus_if.h device_if.h opt_usb.h
MAN4= ng_ubt.4
.include <bsd.kmod.mk>

View File

@ -0,0 +1,254 @@
/*
* bluetooth.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_bluetooth.c,v 1.1.1.1 2002/09/04 21:47:41 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include "ng_bluetooth.h"
/*
* Bluetooth stack sysctl globals
*/
static u_int32_t bluetooth_hci_command_timeout_value = 5; /* sec */
static u_int32_t bluetooth_hci_connect_timeout_value = 60; /* sec */
static u_int32_t bluetooth_hci_watchdog_timeout_value = 60; /* sec */
static u_int32_t bluetooth_hci_max_neighbor_age_value = 600; /* sec */
static u_int32_t bluetooth_l2cap_rtx_timeout_value = 60; /* sec */
static u_int32_t bluetooth_l2cap_ertx_timeout_value = 300; /* sec */
/*
* Define sysctl tree that shared by other parts of Bluetooth stack
*/
SYSCTL_NODE(_net, OID_AUTO, bluetooth, CTLFLAG_RW, 0, "Bluetooth family");
SYSCTL_INT(_net_bluetooth, OID_AUTO, version,
CTLFLAG_RD, 0, NG_BLUETOOTH_VERSION, "");
/*
* HCI
*/
SYSCTL_NODE(_net_bluetooth, OID_AUTO, hci, CTLFLAG_RW,
0, "Bluetooth HCI family");
static int
bluetooth_set_hci_command_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_hci_command_timeout_value;
error = sysctl_handle_int(oidp, &value, sizeof(value), req);
if (error == 0 && req->newptr != NULL) {
if (value > 0)
bluetooth_hci_command_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_hci_command_timeout_value */
SYSCTL_PROC(_net_bluetooth_hci, OID_AUTO, command_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_hci_command_timeout_value, 5,
bluetooth_set_hci_command_timeout_value,
"I", "HCI command timeout (sec)");
static int
bluetooth_set_hci_connect_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_hci_connect_timeout_value;
error = sysctl_handle_int(oidp, &value, sizeof(value), req);
if (error == 0 && req->newptr != NULL) {
if (0 < value && value <= bluetooth_l2cap_rtx_timeout_value)
bluetooth_hci_connect_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_hci_connect_timeout_value */
SYSCTL_PROC(_net_bluetooth_hci, OID_AUTO, connection_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_hci_connect_timeout_value, 60,
bluetooth_set_hci_connect_timeout_value,
"I", "HCI connect timeout (sec)");
SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, watchdog_timeout, CTLFLAG_RW,
&bluetooth_hci_watchdog_timeout_value, 60,
"HCI connection watchdog timeout (sec)");
SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, max_neighbor_age, CTLFLAG_RW,
&bluetooth_hci_max_neighbor_age_value, 600,
"Maximal HCI neighbor cache entry age (sec)");
/*
* L2CAP
*/
SYSCTL_NODE(_net_bluetooth, OID_AUTO, l2cap, CTLFLAG_RW,
0, "Bluetooth L2CAP family");
static int
bluetooth_set_l2cap_rtx_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_l2cap_rtx_timeout_value;
error = sysctl_handle_int(oidp, &value, sizeof(value), req);
if (error == 0 && req->newptr != NULL) {
if (bluetooth_hci_connect_timeout_value <= value &&
value <= bluetooth_l2cap_ertx_timeout_value)
bluetooth_l2cap_rtx_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_l2cap_rtx_timeout_value */
SYSCTL_PROC(_net_bluetooth_l2cap, OID_AUTO, rtx_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_l2cap_rtx_timeout_value, 60,
bluetooth_set_l2cap_rtx_timeout_value,
"I", "L2CAP RTX timeout (sec)");
static int
bluetooth_set_l2cap_ertx_timeout_value(SYSCTL_HANDLER_ARGS)
{
u_int32_t value;
int error;
value = bluetooth_l2cap_ertx_timeout_value;
error = sysctl_handle_int(oidp, &value, sizeof(value), req);
if (error == 0 && req->newptr != NULL) {
if (value >= bluetooth_l2cap_rtx_timeout_value)
bluetooth_l2cap_ertx_timeout_value = value;
else
error = EINVAL;
}
return (error);
} /* bluetooth_set_l2cap_ertx_timeout_value */
SYSCTL_PROC(_net_bluetooth_l2cap, OID_AUTO, ertx_timeout,
CTLTYPE_INT | CTLFLAG_RW,
&bluetooth_l2cap_ertx_timeout_value, 300,
bluetooth_set_l2cap_ertx_timeout_value,
"I", "L2CAP ERTX timeout (sec)");
/*
* Return various sysctl values
*/
u_int32_t
bluetooth_hci_command_timeout(void)
{
return (bluetooth_hci_command_timeout_value * hz);
} /* bluetooth_hci_command_timeout */
u_int32_t
bluetooth_hci_connect_timeout(void)
{
return (bluetooth_hci_connect_timeout_value * hz);
} /* bluetooth_hci_connect_timeout */
u_int32_t
bluetooth_hci_watchdog_timeout(void)
{
return (bluetooth_hci_watchdog_timeout_value * hz);
} /* bluetooth_hci_watchdog_timeout */
u_int32_t
bluetooth_hci_max_neighbor_age(void)
{
return (bluetooth_hci_max_neighbor_age_value);
} /* bluetooth_hci_max_neighbor_age */
u_int32_t
bluetooth_l2cap_rtx_timeout(void)
{
return (bluetooth_l2cap_rtx_timeout_value * hz);
} /* bluetooth_l2cap_rtx_timeout */
u_int32_t
bluetooth_l2cap_ertx_timeout(void)
{
return (bluetooth_l2cap_ertx_timeout_value * hz);
} /* bluetooth_l2cap_ertx_timeout */
/*
* Handle loading and unloading for this code.
*/
static int
bluetooth_modevent(module_t mod, int event, void *data)
{
int error = 0;
switch (event) {
case MOD_LOAD:
break;
case MOD_UNLOAD:
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
} /* bluetooth_modevent */
/*
* Module
*/
static moduledata_t bluetooth_mod = {
"bluetooth",
bluetooth_modevent,
NULL
};
DECLARE_MODULE(ng_bluetooth, bluetooth_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_VERSION(ng_bluetooth, NG_BLUETOOTH_VERSION);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
/*
* ng_bt3c_var.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_bt3c_var.h,v 1.1 2002/11/09 19:07:56 max Exp $
* $FreeBSD$
*
* XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*
* Based on information obrained from: Jose Orlando Pereira <jop@di.uminho.pt>
* and disassembled w2k driver.
*
* XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*
*/
#ifndef _NG_BT3C_VAR_H_
#define _NG_BT3C_VAR_H_
/* Debug printf's */
#define NG_BT3C_ALERT if (sc->debug >= NG_BT3C_ALERT_LEVEL) device_printf
#define NG_BT3C_ERR if (sc->debug >= NG_BT3C_ERR_LEVEL) device_printf
#define NG_BT3C_WARN if (sc->debug >= NG_BT3C_WARN_LEVEL) device_printf
#define NG_BT3C_INFO if (sc->debug >= NG_BT3C_INFO_LEVEL) device_printf
/* Device registers */
#define BT3C_DATA_L 0x00 /* data low byte */
#define BT3C_DATA_H 0x01 /* high byte */
#define BT3C_ADDR_L 0x02 /* address low byte */
#define BT3C_ADDR_H 0x03 /* high byte */
#define BT3C_CONTROL 0x04 /* control */
#define BT3C_FIFO_SIZE 256
/* Device softc structure */
struct bt3c_softc {
/* Device specific */
device_t dev; /* pointer back to device */
int iobase_rid; /* iobase RID */
struct resource *iobase; /* iobase */
int irq_rid; /* irq RID */
struct resource *irq; /* irq */
void *irq_cookie; /* irq cookie */
/* Netgraph specific */
node_p node; /* pointer back to node */
hook_p hook; /* hook */
ng_bt3c_node_debug_ep debug; /* debug level */
u_int16_t flags; /* device flags */
#define BT3C_ANTENNA_OUT (1 << 0) /* antena is out */
#define BT3C_XMIT (1 << 1) /* xmit in progress */
ng_bt3c_node_state_ep state; /* receiving state */
ng_bt3c_node_stat_ep stat; /* statistic */
#define NG_BT3C_STAT_PCKTS_SENT(s) (s).pckts_sent ++
#define NG_BT3C_STAT_BYTES_SENT(s, n) (s).bytes_sent += (n)
#define NG_BT3C_STAT_PCKTS_RECV(s) (s).pckts_recv ++
#define NG_BT3C_STAT_BYTES_RECV(s, n) (s).bytes_recv += (n)
#define NG_BT3C_STAT_OERROR(s) (s).oerrors ++
#define NG_BT3C_STAT_IERROR(s) (s).ierrors ++
#define NG_BT3C_STAT_RESET(s) bzero(&(s), sizeof((s)))
u_int32_t status; /* from ISR */
void *ith; /* ithread handler */
struct mbuf *m; /* current frame */
u_int32_t want; /* # of chars we want */
struct ifqueue inq; /* queue of incoming mbuf's */
struct ifqueue outq; /* queue of outgoing mbuf's */
#define BT3C_DEFAULTQLEN 12 /* XXX max. size of out queue */
};
typedef struct bt3c_softc bt3c_softc_t;
typedef struct bt3c_softc * bt3c_softc_p;
#endif /* ndef _NG_BT3C_VAR_H_ */

View File

@ -0,0 +1,13 @@
# $FreeBSD$
$Id: TODO,v 1.6 2002/06/27 09:50:17 max Exp $
FIXME/TODO list
This is a list of open issues for H4 node
1) Locking/SMP
External code now uses ng_send_fn to inject data into Netgraph, but
i still use splXXX to lock tty level. this is wrong and should be
fixed!

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
/*
* ng_h4_prse.h
*
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_h4_prse.h,v 1.6 2002/09/04 21:35:01 max Exp $
* $FreeBSD$
*/
/***************************************************************************
***************************************************************************
** ng_parse definitions for the H4 node
***************************************************************************
***************************************************************************/
#ifndef _NETGRAPH_H4_PRSE_H_
#define _NETGRAPH_H4_PRSE_H_ 1
/*
* H4 node command list
*/
/* Stat info */
static const struct ng_parse_struct_field ng_h4_stat_type_fields[] =
{
{ "pckts_recv", &ng_parse_uint32_type, },
{ "bytes_recv", &ng_parse_uint32_type, },
{ "pckts_sent", &ng_parse_uint32_type, },
{ "bytes_sent", &ng_parse_uint32_type, },
{ "oerrors", &ng_parse_uint32_type, },
{ "ierrors", &ng_parse_uint32_type, },
{ NULL, }
};
static const struct ng_parse_type ng_h4_stat_type = {
&ng_parse_struct_type,
&ng_h4_stat_type_fields
};
static const struct ng_cmdlist ng_h4_cmdlist[] = {
{
NGM_H4_COOKIE,
NGM_H4_NODE_RESET,
"reset",
NULL,
NULL
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_GET_STATE,
"get_state",
NULL,
&ng_parse_uint16_type
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_GET_DEBUG,
"get_debug",
NULL,
&ng_parse_uint16_type
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_SET_DEBUG,
"set_debug",
&ng_parse_uint16_type,
NULL
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_GET_QLEN,
"get_qlen",
NULL,
&ng_parse_int32_type
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_SET_QLEN,
"set_qlen",
&ng_parse_int32_type,
NULL
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_GET_STAT,
"get_stat",
NULL,
&ng_h4_stat_type
},
{
NGM_H4_COOKIE,
NGM_H4_NODE_RESET_STAT,
"reset_stat",
NULL,
NULL
},
{ 0, }
};
#endif /* ndef _NETGRAPH_H4_PRSE_H_ */

View File

@ -0,0 +1,100 @@
/*
* ng_h4_var.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_h4_var.h,v 1.14 2002/11/03 02:16:31 max Exp $
* $FreeBSD$
*
* Based on:
* ---------
*
* FreeBSD: src/sys/netgraph/ng_tty.h
* Author: Archie Cobbs <archie@freebsd.org>
*/
#ifndef _NETGRAPH_H4_VAR_H_
#define _NETGRAPH_H4_VAR_H_ 1
/*
* Malloc declaration
*/
#ifndef NG_SEPARATE_MALLOC
MALLOC_DECLARE(M_NETGRAPH_H4);
#else
#define M_NETGRAPH_H4 M_NETGRAPH
#endif /* NG_SEPARATE_MALLOC */
/*
* Debug
*/
#define NG_H4_ALERT if (sc->debug >= NG_H4_ALERT_LEVEL) printf
#define NG_H4_ERR if (sc->debug >= NG_H4_ERR_LEVEL) printf
#define NG_H4_WARN if (sc->debug >= NG_H4_WARN_LEVEL) printf
#define NG_H4_INFO if (sc->debug >= NG_H4_INFO_LEVEL) printf
#define NG_H4_HIWATER 256 /* High water mark on output */
/*
* Per-node private info
*/
typedef struct ng_h4_info {
struct tty *tp; /* Terminal device */
node_p node; /* Netgraph node */
u_int32_t flags; /* Flags */
#define NG_H4_TIMEOUT (1 << 0) /* A timeout is pending */
ng_h4_node_debug_ep debug; /* Debug level */
ng_h4_node_state_ep state; /* State */
ng_h4_node_stat_ep stat;
#define NG_H4_STAT_PCKTS_SENT(s) (s).pckts_sent ++
#define NG_H4_STAT_BYTES_SENT(s, n) (s).bytes_sent += (n)
#define NG_H4_STAT_PCKTS_RECV(s) (s).pckts_recv ++
#define NG_H4_STAT_BYTES_RECV(s, n) (s).bytes_recv += (n)
#define NG_H4_STAT_OERROR(s) (s).oerrors ++
#define NG_H4_STAT_IERROR(s) (s).ierrors ++
#define NG_H4_STAT_RESET(s) bzero(&(s), sizeof((s)))
ng_bt_mbufq_t outq; /* Queue of outgoing mbuf's */
#define NG_H4_DEFAULTQLEN 12 /* XXX max number of mbuf's in outq */
#define NG_H4_IBUF_SIZE 1024 /* XXX must be big enough to hold full
frame */
u_int8_t ibuf[NG_H4_IBUF_SIZE]; /* Incoming data */
u_int32_t got; /* Number of bytes we have received */
u_int32_t want; /* Number of bytes we want to receive */
hook_p hook; /* Upstream hook */
struct callout_handle timo; /* See man timeout(9) */
} ng_h4_info_t;
typedef ng_h4_info_t * ng_h4_info_p;
#endif /* _NETGRAPH_H4_VAR_H_ */

View File

@ -0,0 +1,30 @@
# $FreeBSD$
$Id: TODO,v 1.1.1.1 2002/06/09 20:21:47 max Exp $
1) SMP/Locking
The code makes use of ng_send_fn() whenever possible. Just
need to verify and make sure i did it right
2) Review USB ATTACH function
It is a bit ugly now. Probably need a better way to discover
USB device configuration.
2) Firmware upgrade
According to Bluetooth spec device may present third interface
to perform firmware upgrade. 3Com USB Bluetooth dongle has
such interface. Need to implement set of Netgraph messages.
3) Understand and fix isoc. USB transfers (SCO data)
Currenty device reports that is got zero bytes and calls
isoc_in_complete callback over and over again. Why?
Also might need to setup at least two isoc. transfers in
both directions and switch them on the fly. Just to ensure
there at least one transfer at any time ready to run.
4) Currently interrupt transfers are done as bulk-in transfers
Need to check if that is allowed.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,143 @@
/*
* ng_ubt_var.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_ubt_var.h,v 1.1 2002/11/09 19:09:02 max Exp $
* $FreeBSD$
*/
#ifndef _NG_UBT_VAR_H_
#define _NG_UBT_VAR_H_
/* pullup wrapper */
#define NG_UBT_M_PULLUP(m, s) \
do { \
if ((m)->m_len < (s)) \
(m) = m_pullup((m), (s)); \
if ((m) == NULL) \
NG_UBT_ALERT("%s: %s - m_pullup(%d) failed\n", \
__func__, USBDEVNAME(sc->sc_dev), (s)); \
} while (0)
/* Debug printf's */
#define NG_UBT_ALERT if (sc->sc_debug >= NG_UBT_ALERT_LEVEL) printf
#define NG_UBT_ERR if (sc->sc_debug >= NG_UBT_ERR_LEVEL) printf
#define NG_UBT_WARN if (sc->sc_debug >= NG_UBT_WARN_LEVEL) printf
#define NG_UBT_INFO if (sc->sc_debug >= NG_UBT_INFO_LEVEL) printf
/* Bluetooth USB control request type */
#define UBT_HCI_REQUEST 0x20
#define UBT_DEFAULT_QLEN 12
/* USB device softc structure */
struct ubt_softc {
/* State */
ng_ubt_node_debug_ep sc_debug; /* debug level */
u_int32_t sc_flags; /* device flags */
#define UBT_NEED_FRAME_TYPE (1 << 0) /* device required frame type */
#define UBT_HAVE_FRAME_TYPE UBT_NEED_FRAME_TYPE
#define UBT_CMD_XMIT (1 << 1) /* CMD xmit in progress */
#define UBT_ACL_XMIT (1 << 2) /* ACL xmit in progress */
#define UBT_SCO_XMIT (1 << 3) /* SCO xmit in progress */
ng_ubt_node_stat_ep sc_stat; /* statistic */
#define NG_UBT_STAT_PCKTS_SENT(s) (s).pckts_sent ++
#define NG_UBT_STAT_BYTES_SENT(s, n) (s).bytes_sent += (n)
#define NG_UBT_STAT_PCKTS_RECV(s) (s).pckts_recv ++
#define NG_UBT_STAT_BYTES_RECV(s, n) (s).bytes_recv += (n)
#define NG_UBT_STAT_OERROR(s) (s).oerrors ++
#define NG_UBT_STAT_IERROR(s) (s).ierrors ++
#define NG_UBT_STAT_RESET(s) bzero(&(s), sizeof((s)))
/* USB device specific */
USBBASEDEVICE sc_dev; /* pointer back to USB device */
usbd_device_handle sc_udev; /* USB device handle */
usbd_interface_handle sc_iface0; /* USB interface 0 */
usbd_interface_handle sc_iface1; /* USB interface 1 */
struct ifqueue sc_inq; /* incoming queue */
void *sc_ith; /* SWI interrupt handler */
/* Interrupt pipe (HCI events) */
int sc_intr_ep; /* interrupt endpoint */
usbd_pipe_handle sc_intr_pipe; /* interrupt pipe handle */
usbd_xfer_handle sc_intr_xfer; /* intr xfer */
u_int8_t *sc_intr_buffer; /* interrupt buffer */
#define UBT_INTR_BUFFER_SIZE \
(sizeof(ng_hci_event_pkt_t) + NG_HCI_EVENT_PKT_SIZE)
/* Control pipe (HCI commands) */
usbd_xfer_handle sc_ctrl_xfer; /* control xfer handle */
void *sc_ctrl_buffer; /* control buffer */
struct ifqueue sc_cmdq; /* HCI command queue */
#define UBT_CTRL_BUFFER_SIZE \
(sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE)
/* Bulk in pipe (ACL data) */
int sc_bulk_in_ep; /* bulk-in enpoint */
usbd_pipe_handle sc_bulk_in_pipe; /* bulk-in pipe */
usbd_xfer_handle sc_bulk_in_xfer; /* bulk-in xfer */
void *sc_bulk_in_buffer; /* bulk-in buffer */
/* Bulk out pipe (ACL data) */
int sc_bulk_out_ep; /* bulk-out endpoint */
usbd_pipe_handle sc_bulk_out_pipe; /* bulk-out pipe */
usbd_xfer_handle sc_bulk_out_xfer; /* bulk-out xfer */
void *sc_bulk_out_buffer; /* bulk-out buffer */
struct ifqueue sc_aclq; /* ACL data queue */
#define UBT_BULK_BUFFER_SIZE \
512 /* XXX should be big enough to hold one frame */
/* Isoc. in pipe (SCO data) */
int sc_isoc_in_ep; /* isoc-in endpoint */
usbd_pipe_handle sc_isoc_in_pipe; /* isoc-in pipe */
usbd_xfer_handle sc_isoc_in_xfer; /* isoc-in xfer */
void *sc_isoc_in_buffer; /* isoc-in buffer */
u_int16_t *sc_isoc_in_frlen; /* isoc-in. frame length */
/* Isoc. out pipe (ACL data) */
int sc_isoc_out_ep; /* isoc-out endpoint */
usbd_pipe_handle sc_isoc_out_pipe; /* isoc-out pipe */
usbd_xfer_handle sc_isoc_out_xfer; /* isoc-out xfer */
void *sc_isoc_out_buffer; /* isoc-in buffer */
u_int16_t *sc_isoc_out_frlen; /* isoc-out. frame length */
struct ifqueue sc_scoq; /* SCO data queue */
int sc_isoc_size; /* max. size of isoc. packet */
u_int32_t sc_isoc_nframes; /* num. isoc. frames */
#define UBT_ISOC_BUFFER_SIZE \
(sizeof(ng_hci_scodata_pkt_t) + NG_HCI_SCO_PKT_SIZE)
/* Netgraph specific */
node_p sc_node; /* pointer back to node */
hook_p sc_hook; /* upstream hook */
};
typedef struct ubt_softc ubt_softc_t;
typedef struct ubt_softc * ubt_softc_p;
#endif /* ndef _NG_UBT_VAR_H_ */

View File

@ -0,0 +1,42 @@
# $FreeBSD$
$Id: TODO,v 1.10 2002/09/06 21:03:57 max Exp $
FIXME/TODO list
This is a list of open issues for HCI node
1) Locking/SMP
External code now uses ng_send_fn to inject data into Netgraph, so
it should be fine as long as Netgraph is SMP safe. Just need to
verify it.
3) HCI QoS handling
Some code exists, but i have no idea how it should work. Will
understand and fix later. I only have CSR based hardware and
it does not support QoS.
4) Add proper handling for some HCI commands
HCI testing commands is one example. Also might implement Host to
Host Controller flow control (not sure if it is required).
5) Link security
Manage link keys and PINs. Options:
1) manage keys inside HCI node/unit itself
2) use user space daemon.
3) Mix option 1 and option 2.
6) Implement watchdog routine for HCI connections
Some code exists, but it is not used
7) Code cleanup
Verify return codes from functions
Remove some waringns/errors

View File

@ -0,0 +1,887 @@
/*
* ng_hci_cmds.c
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_hci_cmds.c,v 1.22 2002/10/30 00:18:18 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include "ng_bluetooth.h"
#include "ng_hci.h"
#include "ng_hci_var.h"
#include "ng_hci_cmds.h"
#include "ng_hci_evnt.h"
#include "ng_hci_ulpi.h"
#include "ng_hci_misc.h"
/******************************************************************************
******************************************************************************
** HCI commands processing module
******************************************************************************
******************************************************************************/
#undef min
#define min(a, b) ((a) < (b))? (a) : (b)
static int complete_command (ng_hci_unit_p, int, struct mbuf **);
static int process_link_control_params
(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
static int process_link_policy_params
(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
static int process_hc_baseband_params
(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
static int process_info_params
(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
static int process_status_params
(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
static int process_testing_params
(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
static int process_link_control_status
(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
static int process_link_policy_status
(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
/*
* Send HCI command to the driver.
*/
int
ng_hci_send_command(ng_hci_unit_p unit)
{
struct mbuf *m0 = NULL, *m = NULL;
int free, error = 0;
/* Check if other command is pending */
if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
return (0);
/* Check if unit can accept our command */
NG_HCI_BUFF_CMD_GET(unit->buffer, free);
if (free == 0)
return (0);
/* Check if driver hook is still ok */
if (unit->drv == NULL || NG_HOOK_NOT_VALID(unit->drv)) {
NG_HCI_WARN(
"%s: %s - hook \"%s\" is not connected or valid\n",
__func__, NG_NODE_NAME(unit->node), NG_HCI_HOOK_DRV);
NG_BT_MBUFQ_DRAIN(&unit->cmdq);
return (ENOTCONN);
}
/*
* Get first command from queue, give it to RAW hook then
* make copy of it and send it to the driver
*/
m0 = NG_BT_MBUFQ_FIRST(&unit->cmdq);
if (m0 == NULL)
return (0);
ng_hci_mtap(unit, m0);
m = m_dup(m0, M_DONTWAIT);
if (m != NULL)
NG_SEND_DATA_ONLY(error, unit->drv, m);
else
error = ENOBUFS;
if (error != 0)
NG_HCI_ERR(
"%s: %s - could not send HCI command, error=%d\n",
__func__, NG_NODE_NAME(unit->node), error);
/*
* Even if we were not able to send command we still pretend
* that everything is OK and let timeout handle that.
*/
NG_HCI_BUFF_CMD_USE(unit->buffer, 1);
NG_HCI_STAT_CMD_SENT(unit->stat);
NG_HCI_STAT_BYTES_SENT(unit->stat, m0->m_pkthdr.len);
/*
* Note: ng_hci_command_timeout() will set
* NG_HCI_UNIT_COMMAND_PENDING flag
*/
ng_hci_command_timeout(unit);
return (0);
} /* ng_hci_send_command */
/*
* Process HCI Command_Compete event. Complete HCI command, and do post
* processing on the command parameters (cp) and command return parameters
* (e) if required (for example adjust state).
*/
int
ng_hci_process_command_complete(ng_hci_unit_p unit, struct mbuf *e)
{
ng_hci_command_compl_ep *ep = NULL;
struct mbuf *cp = NULL;
int error = 0;
/* Get event packet and update command buffer info */
NG_HCI_M_PULLUP(e, sizeof(*ep));
if (e == NULL)
return (ENOBUFS); /* XXX this is bad */
ep = mtod(e, ng_hci_command_compl_ep *);
NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts);
/* Check for special NOOP command */
if (ep->opcode == 0x0000) {
NG_FREE_M(e);
goto out;
}
/* Try to match first command item in the queue */
error = complete_command(unit, ep->opcode, &cp);
if (error != 0) {
NG_FREE_M(e);
goto out;
}
/*
* Perform post processing on command parameters and return parameters
* do it only if status is OK (status == 0). Status is the first byte
* of any command return parameters.
*/
ep->opcode = le16toh(ep->opcode);
m_adj(e, sizeof(*ep));
if (*mtod(e, u_int8_t *) == 0) { /* XXX m_pullup here? */
switch (NG_HCI_OGF(ep->opcode)) {
case NG_HCI_OGF_LINK_CONTROL:
error = process_link_control_params(unit,
NG_HCI_OCF(ep->opcode), cp, e);
break;
case NG_HCI_OGF_LINK_POLICY:
error = process_link_policy_params(unit,
NG_HCI_OCF(ep->opcode), cp, e);
break;
case NG_HCI_OGF_HC_BASEBAND:
error = process_hc_baseband_params(unit,
NG_HCI_OCF(ep->opcode), cp, e);
break;
case NG_HCI_OGF_INFO:
error = process_info_params(unit,
NG_HCI_OCF(ep->opcode), cp, e);
break;
case NG_HCI_OGF_STATUS:
error = process_status_params(unit,
NG_HCI_OCF(ep->opcode), cp, e);
break;
case NG_HCI_OGF_TESTING:
error = process_testing_params(unit,
NG_HCI_OCF(ep->opcode), cp, e);
break;
case NG_HCI_OGF_BT_LOGO:
case NG_HCI_OGF_VENDOR:
NG_FREE_M(cp);
NG_FREE_M(e);
break;
default:
NG_FREE_M(cp);
NG_FREE_M(e);
error = EINVAL;
break;
}
} else {
NG_HCI_ERR(
"%s: %s - HCI command failed, OGF=%#x, OCF=%#x, status=%#x\n",
__func__, NG_NODE_NAME(unit->node),
NG_HCI_OGF(ep->opcode), NG_HCI_OCF(ep->opcode),
*mtod(e, u_int8_t *));
NG_FREE_M(cp);
NG_FREE_M(e);
}
out:
ng_hci_send_command(unit);
return (error);
} /* ng_hci_process_command_complete */
/*
* Process HCI Command_Status event. Check the status (mst) and do post
* processing (if required).
*/
int
ng_hci_process_command_status(ng_hci_unit_p unit, struct mbuf *e)
{
ng_hci_command_status_ep *ep = NULL;
struct mbuf *cp = NULL;
int error = 0;
/* Update command buffer info */
NG_HCI_M_PULLUP(e, sizeof(*ep));
if (e == NULL)
return (ENOBUFS); /* XXX this is bad */
ep = mtod(e, ng_hci_command_status_ep *);
NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts);
/* Check for special NOOP command */
if (ep->opcode == 0x0000)
goto out;
/* Try to match first command item in the queue */
error = complete_command(unit, ep->opcode, &cp);
if (error != 0)
goto out;
/*
* Perform post processing on HCI Command_Status event
*/
ep->opcode = le16toh(ep->opcode);
switch (NG_HCI_OGF(ep->opcode)) {
case NG_HCI_OGF_LINK_CONTROL:
error = process_link_control_status(unit, ep, cp);
break;
case NG_HCI_OGF_LINK_POLICY:
error = process_link_policy_status(unit, ep, cp);
break;
case NG_HCI_OGF_BT_LOGO:
case NG_HCI_OGF_VENDOR:
NG_FREE_M(cp);
break;
case NG_HCI_OGF_HC_BASEBAND:
case NG_HCI_OGF_INFO:
case NG_HCI_OGF_STATUS:
case NG_HCI_OGF_TESTING:
default:
NG_FREE_M(cp);
error = EINVAL;
break;
}
out:
NG_FREE_M(e);
ng_hci_send_command(unit);
return (error);
} /* ng_hci_process_command_status */
/*
* Complete queued HCI command.
*/
static int
complete_command(ng_hci_unit_p unit, int opcode, struct mbuf **cp)
{
struct mbuf *m = NULL;
/* Check unit state */
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) {
NG_HCI_ALERT(
"%s: %s - no pending command, state=%#x\n",
__func__, NG_NODE_NAME(unit->node), unit->state);
return (EINVAL);
}
/* Get first command in the queue */
m = NG_BT_MBUFQ_FIRST(&unit->cmdq);
if (m == NULL) {
NG_HCI_ALERT(
"%s: %s - empty command queue?!\n", __func__, NG_NODE_NAME(unit->node));
return (EINVAL);
}
/*
* Match command opcode, if does not match - do nothing and
* let timeout handle that.
*/
if (mtod(m, ng_hci_cmd_pkt_t *)->opcode != opcode) {
NG_HCI_ALERT(
"%s: %s - command queue is out of sync\n", __func__, NG_NODE_NAME(unit->node));
return (EINVAL);
}
/*
* Now we can remove command timeout, dequeue completed command
* and return command parameters. Note: ng_hci_command_untimeout()
* will drop NG_HCI_UNIT_COMMAND_PENDING flag.
*/
ng_hci_command_untimeout(unit);
NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, *cp);
m_adj(*cp, sizeof(ng_hci_cmd_pkt_t));
return (0);
} /* complete_command */
/*
* Process HCI command timeout
*/
void
ng_hci_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
{
ng_hci_unit_p unit = (ng_hci_unit_p) arg1;
struct mbuf *m = NULL;
u_int16_t opcode;
if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) {
NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, m);
if (m == NULL) {
KASSERT(0,
("%s: %s - command queue is out of sync!\n",
__func__, NG_NODE_NAME(unit->node)));
return;
}
opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode);
NG_FREE_M(m);
NG_HCI_ERR(
"%s: %s - unable to complete HCI command OGF=%#x, OCF=%#x. Timeout\n",
__func__, NG_NODE_NAME(unit->node), NG_HCI_OGF(opcode),
NG_HCI_OCF(opcode));
/*
* Try to send more commands
*/
NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
ng_hci_send_command(unit);
} else
KASSERT(0,
("%s: %s - no pending command, state=%#x\n",
__func__, NG_NODE_NAME(unit->node), unit->state));
} /* ng_hci_process_command_timeout */
/*
* Process link command return parameters
*/
static int
process_link_control_params(ng_hci_unit_p unit, u_int16_t ocf,
struct mbuf *mcp, struct mbuf *mrp)
{
int error = 0;
switch (ocf) {
case NG_HCI_OCF_INQUIRY_CANCEL:
case NG_HCI_OCF_PERIODIC_INQUIRY:
case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY:
case NG_HCI_OCF_LINK_KEY_REP:
case NG_HCI_OCF_LINK_KEY_NEG_REP:
case NG_HCI_OCF_PIN_CODE_REP:
case NG_HCI_OCF_PIN_CODE_NEG_REP:
/* These do not need post processing */
break;
case NG_HCI_OCF_INQUIRY:
case NG_HCI_OCF_CREATE_CON:
case NG_HCI_OCF_DISCON:
case NG_HCI_OCF_ADD_SCO_CON:
case NG_HCI_OCF_ACCEPT_CON:
case NG_HCI_OCF_REJECT_CON:
case NG_HCI_OCF_CHANGE_CON_PKT_TYPE:
case NG_HCI_OCF_AUTH_REQ:
case NG_HCI_OCF_SET_CON_ENCRYPTION:
case NG_HCI_OCF_CHANGE_CON_LINK_KEY:
case NG_HCI_OCF_MASTER_LINK_KEY:
case NG_HCI_OCF_REMOTE_NAME_REQ:
case NG_HCI_OCF_READ_REMOTE_FEATURES:
case NG_HCI_OCF_READ_REMOTE_VER_INFO:
case NG_HCI_OCF_READ_CLOCK_OFFSET:
default:
/*
* None of these command was supposed to generate
* Command_Complete event. Instead Command_Status event
* should have been generated and then appropriate event
* should have been sent to indicate the final result.
*/
error = EINVAL;
break;
}
NG_FREE_M(mcp);
NG_FREE_M(mrp);
return (error);
} /* process_link_control_params */
/*
* Process link policy command return parameters
*/
static int
process_link_policy_params(ng_hci_unit_p unit, u_int16_t ocf,
struct mbuf *mcp, struct mbuf *mrp)
{
int error = 0;
switch (ocf){
case NG_HCI_OCF_ROLE_DISCOVERY: {
ng_hci_role_discovery_rp *rp = NULL;
ng_hci_unit_con_t *con = NULL;
u_int16_t h;
NG_HCI_M_PULLUP(mrp, sizeof(*rp));
if (mrp != NULL) {
rp = mtod(mrp, ng_hci_role_discovery_rp *);
h = NG_HCI_CON_HANDLE(le16toh(rp->con_handle));
con = ng_hci_con_by_handle(unit, h);
if (con == NULL) {
NG_HCI_ALERT(
"%s: %s - invalid connection handle=%d\n",
__func__, NG_NODE_NAME(unit->node), h);
error = ENOENT;
} else if (con->link_type != NG_HCI_LINK_ACL) {
NG_HCI_ALERT(
"%s: %s - invalid link type=%d\n", __func__, NG_NODE_NAME(unit->node),
con->link_type);
error = EINVAL;
} else
con->role = rp->role;
} else
error = ENOBUFS;
} break;
case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS:
case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS:
/* These do not need post processing */
break;
case NG_HCI_OCF_HOLD_MODE:
case NG_HCI_OCF_SNIFF_MODE:
case NG_HCI_OCF_EXIT_SNIFF_MODE:
case NG_HCI_OCF_PARK_MODE:
case NG_HCI_OCF_EXIT_PARK_MODE:
case NG_HCI_OCF_QOS_SETUP:
case NG_HCI_OCF_SWITCH_ROLE:
default:
/*
* None of these command was supposed to generate
* Command_Complete event. Instead Command_Status event
* should have been generated and then appropriate event
* should have been sent to indicate the final result.
*/
error = EINVAL;
break;
}
NG_FREE_M(mcp);
NG_FREE_M(mrp);
return (error);
} /* process_link_policy_params */
/*
* Process HC and baseband command return parameters
*/
int
process_hc_baseband_params(ng_hci_unit_p unit, u_int16_t ocf,
struct mbuf *mcp, struct mbuf *mrp)
{
int error = 0;
switch (ocf) {
case NG_HCI_OCF_SET_EVENT_MASK:
case NG_HCI_OCF_SET_EVENT_FILTER:
case NG_HCI_OCF_FLUSH: /* XXX Do we need to handle that? */
case NG_HCI_OCF_READ_PIN_TYPE:
case NG_HCI_OCF_WRITE_PIN_TYPE:
case NG_HCI_OCF_CREATE_NEW_UNIT_KEY:
case NG_HCI_OCF_WRITE_STORED_LINK_KEY:
case NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO:
case NG_HCI_OCF_WRITE_PAGE_TIMO:
case NG_HCI_OCF_READ_SCAN_ENABLE:
case NG_HCI_OCF_WRITE_SCAN_ENABLE:
case NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY:
case NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY:
case NG_HCI_OCF_READ_AUTH_ENABLE:
case NG_HCI_OCF_WRITE_AUTH_ENABLE:
case NG_HCI_OCF_READ_ENCRYPTION_MODE:
case NG_HCI_OCF_WRITE_ENCRYPTION_MODE:
case NG_HCI_OCF_WRITE_VOICE_SETTINGS:
case NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS:
case NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS:
case NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY:
case NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY:
case NG_HCI_OCF_READ_SCO_FLOW_CONTROL:
case NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL:
case NG_HCI_OCF_H2HC_FLOW_CONTROL: /* XXX Not supported this time */
case NG_HCI_OCF_HOST_BUFFER_SIZE:
case NG_HCI_OCF_READ_IAC_LAP:
case NG_HCI_OCF_WRITE_IAC_LAP:
case NG_HCI_OCF_READ_PAGE_SCAN_PERIOD:
case NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD:
case NG_HCI_OCF_READ_PAGE_SCAN:
case NG_HCI_OCF_WRITE_PAGE_SCAN:
case NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO:
case NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO:
case NG_HCI_OCF_READ_SUPPORTED_IAC_NUM:
case NG_HCI_OCF_READ_STORED_LINK_KEY:
case NG_HCI_OCF_DELETE_STORED_LINK_KEY:
case NG_HCI_OCF_READ_CON_ACCEPT_TIMO:
case NG_HCI_OCF_READ_PAGE_TIMO:
case NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY:
case NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY:
case NG_HCI_OCF_READ_VOICE_SETTINGS:
case NG_HCI_OCF_READ_AUTO_FLUSH_TIMO:
case NG_HCI_OCF_WRITE_AUTO_FLUSH_TIMO:
case NG_HCI_OCF_READ_XMIT_LEVEL:
case NG_HCI_OCF_HOST_NUM_COMPL_PKTS: /* XXX Can get here? */
case NG_HCI_OCF_CHANGE_LOCAL_NAME:
case NG_HCI_OCF_READ_LOCAL_NAME:
case NG_HCI_OCF_READ_UNIT_CLASS:
case NG_HCI_OCF_WRITE_UNIT_CLASS:
/* These do not need post processing */
break;
case NG_HCI_OCF_RESET: {
ng_hci_unit_con_p con = NULL;
int size;
/*
* XXX
*
* After RESET command unit goes into standby mode
* and all operational state is lost. Host controller
* will revert to default values for all parameters.
*
* For now we shall terminate all connections and drop
* inited bit. After RESET unit must be re-initialized.
*/
while (!LIST_EMPTY(&unit->con_list)) {
con = LIST_FIRST(&unit->con_list);
/* Connection terminated by local host */
ng_hci_lp_discon_ind(con, 0x16);
ng_hci_free_con(con);
}
NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);
NG_HCI_BUFF_ACL_FREE(unit->buffer, size);
NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);
NG_HCI_BUFF_SCO_FREE(unit->buffer, size);
unit->state &= ~NG_HCI_UNIT_INITED;
} break;
default:
error = EINVAL;
break;
}
NG_FREE_M(mcp);
NG_FREE_M(mrp);
return (error);
} /* process_hc_baseband_params */
/*
* Process info command return parameters
*/
static int
process_info_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
struct mbuf *mrp)
{
int error = 0, len;
switch (ocf) {
case NG_HCI_OCF_READ_LOCAL_VER:
case NG_HCI_OCF_READ_COUNTRY_CODE:
break;
case NG_HCI_OCF_READ_LOCAL_FEATURES:
m_adj(mrp, sizeof(u_int8_t));
len = min(mrp->m_pkthdr.len, sizeof(unit->features));
m_copydata(mrp, 0, len, (caddr_t) unit->features);
break;
case NG_HCI_OCF_READ_BUFFER_SIZE: {
ng_hci_read_buffer_size_rp *rp = NULL;
/* Do not update buffer descriptor if node was initialized */
if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY)
break;
NG_HCI_M_PULLUP(mrp, sizeof(*rp));
if (mrp != NULL) {
rp = mtod(mrp, ng_hci_read_buffer_size_rp *);
NG_HCI_BUFF_ACL_SET(
unit->buffer,
le16toh(rp->num_acl_pkt), /* number */
le16toh(rp->max_acl_size), /* size */
le16toh(rp->num_acl_pkt) /* free */
);
NG_HCI_BUFF_SCO_SET(
unit->buffer,
le16toh(rp->num_sco_pkt), /* number */
rp->max_sco_size, /* size */
le16toh(rp->num_sco_pkt) /* free */
);
/* Let upper layers know */
ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);
ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);
} else
error = ENOBUFS;
} break;
case NG_HCI_OCF_READ_BDADDR:
/* Do not update BD_ADDR if node was initialized */
if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY)
break;
m_adj(mrp, sizeof(u_int8_t));
len = min(mrp->m_pkthdr.len, sizeof(unit->bdaddr));
m_copydata(mrp, 0, len, (caddr_t) &unit->bdaddr);
/* Let upper layers know */
ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);
ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);
break;
default:
error = EINVAL;
break;
}
NG_FREE_M(mcp);
NG_FREE_M(mrp);
return (error);
} /* process_info_params */
/*
* Process status command return parameters
*/
static int
process_status_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
struct mbuf *mrp)
{
int error = 0;
switch (ocf) {
case NG_HCI_OCF_READ_FAILED_CONTACT_CNTR:
case NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR:
case NG_HCI_OCF_GET_LINK_QUALITY:
case NG_HCI_OCF_READ_RSSI:
/* These do not need post processing */
break;
default:
error = EINVAL;
break;
}
NG_FREE_M(mcp);
NG_FREE_M(mrp);
return (error);
} /* process_status_params */
/*
* Process testing command return parameters
*/
int
process_testing_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
struct mbuf *mrp)
{
int error = 0;
switch (ocf) {
/*
* XXX FIXME
* We do not support these features at this time. However,
* HCI node could support this and do something smart. At least
* node can change unit state.
*/
case NG_HCI_OCF_READ_LOOPBACK_MODE:
case NG_HCI_OCF_WRITE_LOOPBACK_MODE:
case NG_HCI_OCF_ENABLE_UNIT_UNDER_TEST:
break;
default:
error = EINVAL;
break;
}
NG_FREE_M(mcp);
NG_FREE_M(mrp);
return (error);
} /* process_testing_params */
/*
* Process link control command status
*/
static int
process_link_control_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep,
struct mbuf *mcp)
{
int error = 0;
switch (NG_HCI_OCF(ep->opcode)) {
case NG_HCI_OCF_INQUIRY:
case NG_HCI_OCF_DISCON: /* XXX */
case NG_HCI_OCF_REJECT_CON: /* XXX */
case NG_HCI_OCF_CHANGE_CON_PKT_TYPE:
case NG_HCI_OCF_AUTH_REQ:
case NG_HCI_OCF_SET_CON_ENCRYPTION:
case NG_HCI_OCF_CHANGE_CON_LINK_KEY:
case NG_HCI_OCF_MASTER_LINK_KEY:
case NG_HCI_OCF_REMOTE_NAME_REQ:
case NG_HCI_OCF_READ_REMOTE_FEATURES:
case NG_HCI_OCF_READ_REMOTE_VER_INFO:
case NG_HCI_OCF_READ_CLOCK_OFFSET:
/* These do not need post processing */
break;
case NG_HCI_OCF_CREATE_CON:
break;
case NG_HCI_OCF_ADD_SCO_CON:
break;
case NG_HCI_OCF_ACCEPT_CON:
break;
case NG_HCI_OCF_INQUIRY_CANCEL:
case NG_HCI_OCF_PERIODIC_INQUIRY:
case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY:
case NG_HCI_OCF_LINK_KEY_REP:
case NG_HCI_OCF_LINK_KEY_NEG_REP:
case NG_HCI_OCF_PIN_CODE_REP:
case NG_HCI_OCF_PIN_CODE_NEG_REP:
default:
/*
* None of these command was supposed to generate
* Command_Status event. Instead Command_Complete event
* should have been sent.
*/
error = EINVAL;
break;
}
NG_FREE_M(mcp);
return (error);
} /* process_link_control_status */
/*
* Process link policy command status
*/
static int
process_link_policy_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep,
struct mbuf *mcp)
{
int error = 0;
switch (NG_HCI_OCF(ep->opcode)) {
case NG_HCI_OCF_HOLD_MODE:
case NG_HCI_OCF_SNIFF_MODE:
case NG_HCI_OCF_EXIT_SNIFF_MODE:
case NG_HCI_OCF_PARK_MODE:
case NG_HCI_OCF_EXIT_PARK_MODE:
case NG_HCI_OCF_SWITCH_ROLE:
/* These do not need post processing */
break;
case NG_HCI_OCF_QOS_SETUP:
break;
case NG_HCI_OCF_ROLE_DISCOVERY:
case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS:
case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS:
default:
/*
* None of these command was supposed to generate
* Command_Status event. Instead Command_Complete event
* should have been sent.
*/
error = EINVAL;
break;
}
NG_FREE_M(mcp);
return (error);
} /* process_link_policy_status */

View File

@ -0,0 +1,45 @@
/*
* ng_hci_cmds.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_hci_cmds.h,v 1.6 2002/09/04 21:36:51 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_CMDS_H_
#define _NETGRAPH_HCI_CMDS_H_ 1
/*
* HCI command return parameters processing routines
*/
int ng_hci_send_command (ng_hci_unit_p);
int ng_hci_process_command_complete (ng_hci_unit_p, struct mbuf *);
int ng_hci_process_command_status (ng_hci_unit_p, struct mbuf *);
void ng_hci_process_command_timeout (node_p, hook_p, void *, int);
#endif /* ndef _NETGRAPH_HCI_CMDS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
/*
* ng_hci_evnt.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_hci_evnt.h,v 1.4 2002/09/04 21:36:51 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_EVNT_H_
#define _NETGRAPH_HCI_EVNT_H_ 1
/*
* HCI events processing routines
*/
int ng_hci_process_event (ng_hci_unit_p, struct mbuf *);
void ng_hci_send_data (ng_hci_unit_p);
#endif /* ndef _NETGRAPH_HCI_EVNT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,556 @@
/*
* ng_hci_misc.c
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_hci_misc.c,v 1.18 2002/10/30 00:18:19 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include "ng_bluetooth.h"
#include "ng_hci.h"
#include "ng_hci_var.h"
#include "ng_hci_cmds.h"
#include "ng_hci_evnt.h"
#include "ng_hci_ulpi.h"
#include "ng_hci_misc.h"
/******************************************************************************
******************************************************************************
** Utility routines
******************************************************************************
******************************************************************************/
static void ng_hci_command_queue_timeout (void *);
static void ng_hci_con_queue_timeout (void *);
static void ng_hci_con_queue_watchdog_timeout (void *);
/*
* Give packet to RAW hook
* Assumes input mbuf is read only.
*/
void
ng_hci_mtap(ng_hci_unit_p unit, struct mbuf *m0)
{
struct mbuf *m = NULL;
int error = 0;
if (unit->raw != NULL && NG_HOOK_IS_VALID(unit->raw)) {
m = m_dup(m0, M_DONTWAIT);
if (m != NULL)
NG_SEND_DATA_ONLY(error, unit->raw, m);
if (error != 0)
NG_HCI_INFO(
"%s: %s - Could not forward packet, error=%d\n",
__func__, NG_NODE_NAME(unit->node), error);
}
} /* ng_hci_mtap */
/*
* Send notification to the upper layer's
*/
void
ng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2)
{
ng_hci_unit_p unit = NULL;
struct ng_mesg *msg = NULL;
ng_hci_node_up_ep *ep = NULL;
int error;
if (node == NULL || NG_NODE_NOT_VALID(node) ||
hook == NULL || NG_HOOK_NOT_VALID(hook))
return;
unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY)
return;
if (hook != unit->acl && hook != unit->sco)
return;
NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_NOWAIT);
if (msg != NULL) {
ep = (ng_hci_node_up_ep *)(msg->data);
if (hook == unit->acl) {
NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size);
NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts);
} else {
NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size);
NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts);
}
bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
NG_SEND_MSG_HOOK(error, node, msg, hook, NULL);
} else
error = ENOMEM;
if (error != 0)
NG_HCI_INFO(
"%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n",
__func__, NG_NODE_NAME(unit->node),
NG_HOOK_NAME(hook), error);
} /* ng_hci_node_is_up */
/*
* Clean unit (helper)
*/
void
ng_hci_unit_clean(ng_hci_unit_p unit, int reason)
{
int size;
/* Drain command queue */
if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
ng_hci_command_untimeout(unit);
NG_BT_MBUFQ_DRAIN(&unit->cmdq);
NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
/* Clean up connection list */
while (!LIST_EMPTY(&unit->con_list)) {
ng_hci_unit_con_p con = LIST_FIRST(&unit->con_list);
/*
* Notify upper layer protocol and destroy connection
* descriptor. Do not really care about the result.
*/
ng_hci_lp_discon_ind(con, reason);
ng_hci_free_con(con);
}
NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);
NG_HCI_BUFF_ACL_FREE(unit->buffer, size);
NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);
NG_HCI_BUFF_SCO_FREE(unit->buffer, size);
/* Clean up neighbors list */
ng_hci_flush_neighbor_cache(unit);
} /* ng_hci_unit_clean */
/*
* Allocate and link new unit neighbor cache entry
*/
ng_hci_neighbor_p
ng_hci_new_neighbor(ng_hci_unit_p unit)
{
ng_hci_neighbor_p n = NULL;
MALLOC(n, ng_hci_neighbor_p, sizeof(*n), M_NETGRAPH_HCI,
M_NOWAIT | M_ZERO);
if (n != NULL) {
getmicrotime(&n->updated);
LIST_INSERT_HEAD(&unit->neighbors, n, next);
}
return (n);
} /* ng_hci_new_neighbor */
/*
* Free unit neighbor cache entry
*/
void
ng_hci_free_neighbor(ng_hci_neighbor_p n)
{
LIST_REMOVE(n, next);
bzero(n, sizeof(*n));
FREE(n, M_NETGRAPH_HCI);
} /* ng_hci_free_neighbor */
/*
* Flush neighbor cache
*/
void
ng_hci_flush_neighbor_cache(ng_hci_unit_p unit)
{
while (!LIST_EMPTY(&unit->neighbors))
ng_hci_free_neighbor(LIST_FIRST(&unit->neighbors));
} /* ng_hci_flush_neighbor_cache */
/*
* Lookup unit in neighbor cache
*/
ng_hci_neighbor_p
ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr)
{
ng_hci_neighbor_p n = NULL;
for (n = LIST_FIRST(&unit->neighbors); n != NULL; ) {
ng_hci_neighbor_p nn = LIST_NEXT(n, next);
if (!ng_hci_neighbor_stale(n)) {
if (bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0)
break;
} else
ng_hci_free_neighbor(n); /* remove old entry */
n = nn;
}
return (n);
} /* ng_hci_get_neighbor */
/*
* Check if neighbor entry is stale
*/
int
ng_hci_neighbor_stale(ng_hci_neighbor_p n)
{
struct timeval now;
getmicrotime(&now);
return (now.tv_sec - n->updated.tv_sec > bluetooth_hci_max_neighbor_age());
} /* ng_hci_neighbor_stale */
/*
* Allocate and link new connection descriptor
*/
ng_hci_unit_con_p
ng_hci_new_con(ng_hci_unit_p unit, int link_type)
{
ng_hci_unit_con_p con = NULL;
int num_pkts;
MALLOC(con, ng_hci_unit_con_p, sizeof(*con), M_NETGRAPH_HCI,
M_NOWAIT | M_ZERO);
if (con != NULL) {
con->unit = unit;
con->state = NG_HCI_CON_CLOSED;
con->link_type = link_type;
if (con->link_type == NG_HCI_LINK_ACL)
NG_HCI_BUFF_ACL_TOTAL(unit->buffer, num_pkts);
else
NG_HCI_BUFF_SCO_TOTAL(unit->buffer, num_pkts);
NG_BT_ITEMQ_INIT(&con->conq, num_pkts);
callout_handle_init(&con->con_timo);
callout_handle_init(&con->watchdog_timo);
LIST_INSERT_HEAD(&unit->con_list, con, next);
}
return (con);
} /* ng_hci_new_con */
/*
* Free connection descriptor
*/
void
ng_hci_free_con(ng_hci_unit_con_p con)
{
LIST_REMOVE(con, next);
/* Remove all timeouts (if any) */
if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
ng_hci_con_untimeout(con);
if (con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING)
ng_hci_con_watchdog_untimeout(con);
/*
* If we have pending packets then assume that Host Controller has
* flushed these packets and we can free them too
*/
if (con->link_type == NG_HCI_LINK_ACL)
NG_HCI_BUFF_ACL_FREE(con->unit->buffer, con->pending);
else
NG_HCI_BUFF_SCO_FREE(con->unit->buffer, con->pending);
NG_BT_ITEMQ_DESTROY(&con->conq);
bzero(con, sizeof(*con));
FREE(con, M_NETGRAPH_HCI);
} /* ng_hci_free_con */
/*
* Lookup connection for given unit and connection handle.
*/
ng_hci_unit_con_p
ng_hci_con_by_handle(ng_hci_unit_p unit, int con_handle)
{
ng_hci_unit_con_p con = NULL;
LIST_FOREACH(con, &unit->con_list, next)
if (con->con_handle == con_handle)
break;
return (con);
} /* ng_hci_con_by_handle */
/*
* Lookup connection for given unit, link type and remove unit address
*/
ng_hci_unit_con_p
ng_hci_con_by_bdaddr(ng_hci_unit_p unit, bdaddr_p bdaddr, int link_type)
{
ng_hci_unit_con_p con = NULL;
LIST_FOREACH(con, &unit->con_list, next)
if (con->link_type == link_type &&
bcmp(&con->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
break;
return (con);
} /* ng_hci_con_by_bdaddr */
/*
* Set HCI command timeout
*/
void
ng_hci_command_timeout(ng_hci_unit_p unit)
{
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) {
NG_NODE_REF(unit->node);
unit->state |= NG_HCI_UNIT_COMMAND_PENDING;
unit->cmd_timo = timeout(ng_hci_command_queue_timeout, unit,
bluetooth_hci_command_timeout());
} else
KASSERT(0,
("%s: %s - Duplicated command timeout!\n", __func__, NG_NODE_NAME(unit->node)));
} /* ng_hci_command_timeout */
/*
* Unset HCI command timeout
*/
void
ng_hci_command_untimeout(ng_hci_unit_p unit)
{
if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) {
unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
untimeout(ng_hci_command_queue_timeout, unit, unit->cmd_timo);
NG_NODE_UNREF(unit->node);
} else
KASSERT(0,
("%s: %s - No command timeout!\n", __func__, NG_NODE_NAME(unit->node)));
} /* ng_hci_command_untimeout */
/*
* OK timeout has happend, so queue timeout processing function
*/
static void
ng_hci_command_queue_timeout(void *context)
{
ng_hci_unit_p unit = (ng_hci_unit_p) context;
node_p node = unit->node;
if (NG_NODE_IS_VALID(node))
ng_send_fn(node,NULL,&ng_hci_process_command_timeout,unit,0);
NG_NODE_UNREF(node);
} /* ng_hci_command_queue_timeout */
/*
* Set HCI connection timeout
*/
void
ng_hci_con_timeout(ng_hci_unit_con_p con)
{
if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) {
NG_NODE_REF(con->unit->node);
con->flags |= NG_HCI_CON_TIMEOUT_PENDING;
con->con_timo = timeout(ng_hci_con_queue_timeout, con,
bluetooth_hci_connect_timeout());
} else
KASSERT(0,
("%s: %s - Duplicated connection timeout!\n",
__func__, NG_NODE_NAME(con->unit->node)));
} /* ng_hci_con_timeout */
/*
* Unset HCI connection timeout
*/
void
ng_hci_con_untimeout(ng_hci_unit_con_p con)
{
if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) {
con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;
untimeout(ng_hci_con_queue_timeout, con, con->con_timo);
NG_NODE_UNREF(con->unit->node);
} else
KASSERT(0,
("%s: %s - No connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node)));
} /* ng_hci_con_untimeout */
/*
* OK timeout has happend, so queue timeout processing function
*/
static void
ng_hci_con_queue_timeout(void *context)
{
ng_hci_unit_con_p con = (ng_hci_unit_con_p) context;
node_p node = con->unit->node;
if (NG_NODE_IS_VALID(node))
ng_send_fn(node, NULL, &ng_hci_process_con_timeout, con, 0);
NG_NODE_UNREF(node);
} /* ng_hci_con_queue_timeout */
/*
* Set HCI connection watchdog timeout
*/
void
ng_hci_con_watchdog_timeout(ng_hci_unit_con_p con)
{
if (!(con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING)) {
NG_NODE_REF(con->unit->node);
con->flags |= NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING;
con->watchdog_timo = timeout(ng_hci_con_queue_watchdog_timeout,
con, bluetooth_hci_watchdog_timeout());
} else
KASSERT(0,
("%s: %s - Duplicated connection watchdog timeout!\n",
__func__, NG_NODE_NAME(con->unit->node)));
} /* ng_hci_con_watchdog_timeout */
/*
* Unset HCI connection watchdog timeout
*/
void
ng_hci_con_watchdog_untimeout(ng_hci_unit_con_p con)
{
if (con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING) {
con->flags &= ~NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING;
untimeout(ng_hci_con_queue_watchdog_timeout, con,
con->watchdog_timo);
NG_NODE_UNREF(con->unit->node);
} else
KASSERT(0,
("%s: %s - No connection watchdog timeout!\n",
__func__, NG_NODE_NAME(con->unit->node)));
} /* ng_hci_con_watchdog_untimeout */
/*
* OK timeout has happend, so queue timeout processing function
*/
static void
ng_hci_con_queue_watchdog_timeout(void *context)
{
ng_hci_unit_con_p con = (ng_hci_unit_con_p) context;
node_p node = con->unit->node;
if (NG_NODE_IS_VALID(node))
ng_send_fn(node, NULL, &ng_hci_process_con_watchdog_timeout,
con, 0);
NG_NODE_UNREF(node);
} /* ng_hci_con_queue_watchdog_timeout */
#if 0
/*
* Convert numeric error code/reason to a string
*/
char const * const
ng_hci_str_error(u_int16_t code)
{
#define LAST_ERROR_CODE ((sizeof(s)/sizeof(s[0]))-1)
static char const * const s[] = {
/* 0x00 */ "No error",
/* 0x01 */ "Unknown HCI command",
/* 0x02 */ "No connection",
/* 0x03 */ "Hardware failure",
/* 0x04 */ "Page timeout",
/* 0x05 */ "Authentication failure",
/* 0x06 */ "Key missing",
/* 0x07 */ "Memory full",
/* 0x08 */ "Connection timeout",
/* 0x09 */ "Max number of connections",
/* 0x0a */ "Max number of SCO connections to a unit",
/* 0x0b */ "ACL connection already exists",
/* 0x0c */ "Command disallowed",
/* 0x0d */ "Host rejected due to limited resources",
/* 0x0e */ "Host rejected due to securiity reasons",
/* 0x0f */ "Host rejected due to remote unit is a personal unit",
/* 0x10 */ "Host timeout",
/* 0x11 */ "Unsupported feature or parameter value",
/* 0x12 */ "Invalid HCI command parameter",
/* 0x13 */ "Other end terminated connection: User ended connection",
/* 0x14 */ "Other end terminated connection: Low resources",
/* 0x15 */ "Other end terminated connection: About to power off",
/* 0x16 */ "Connection terminated by local host",
/* 0x17 */ "Repeated attempts",
/* 0x18 */ "Pairing not allowed",
/* 0x19 */ "Unknown LMP PDU",
/* 0x1a */ "Unsupported remote feature",
/* 0x1b */ "SCO offset rejected",
/* 0x1c */ "SCO interval rejected",
/* 0x1d */ "SCO air mode rejected",
/* 0x1e */ "Invalid LMP parameters",
/* 0x1f */ "Unspecified error",
/* 0x20 */ "Unsupported LMP parameter value",
/* 0x21 */ "Role change not allowed",
/* 0x22 */ "LMP response timeout",
/* 0x23 */ "LMP error transaction collision",
/* 0x24 */ "LMP PSU not allowed",
/* 0x25 */ "Encryption mode not acceptable",
/* 0x26 */ "Unit key used",
/* 0x27 */ "QoS is not supported",
/* 0x28 */ "Instant passed",
/* 0x29 */ "Paring with unit key not supported",
/* SHOULD ALWAYS BE LAST */ "Unknown error"
};
return ((code >= LAST_ERROR_CODE)? s[LAST_ERROR_CODE] : s[code]);
} /* ng_hci_str_error */
#endif

View File

@ -0,0 +1,58 @@
/*
* ng_hci_misc.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_hci_misc.h,v 1.8 2002/09/04 21:36:52 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_MISC_H_
#define _NETGRAPH_HCI_MISC_H_ 1
void ng_hci_mtap (ng_hci_unit_p, struct mbuf *);
void ng_hci_node_is_up (node_p, hook_p, void *, int);
void ng_hci_unit_clean (ng_hci_unit_p, int);
ng_hci_neighbor_p ng_hci_new_neighbor (ng_hci_unit_p);
void ng_hci_free_neighbor (ng_hci_neighbor_p);
void ng_hci_flush_neighbor_cache (ng_hci_unit_p);
ng_hci_neighbor_p ng_hci_get_neighbor (ng_hci_unit_p, bdaddr_p);
int ng_hci_neighbor_stale (ng_hci_neighbor_p);
ng_hci_unit_con_p ng_hci_new_con (ng_hci_unit_p, int);
void ng_hci_free_con (ng_hci_unit_con_p);
ng_hci_unit_con_p ng_hci_con_by_handle (ng_hci_unit_p, int);
ng_hci_unit_con_p ng_hci_con_by_bdaddr (ng_hci_unit_p, bdaddr_p, int);
void ng_hci_command_timeout (ng_hci_unit_p);
void ng_hci_command_untimeout (ng_hci_unit_p);
void ng_hci_con_timeout (ng_hci_unit_con_p);
void ng_hci_con_untimeout (ng_hci_unit_con_p);
void ng_hci_con_watchdog_timeout (ng_hci_unit_con_p);
void ng_hci_con_watchdog_untimeout (ng_hci_unit_con_p);
#endif /* ndef _NETGRAPH_HCI_MISC_H_ */

View File

@ -0,0 +1,203 @@
/*
* ng_hci_prse.h
*
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_hci_prse.h,v 1.9 2002/11/12 22:35:40 max Exp $
* $FreeBSD$
*/
/***************************************************************************
***************************************************************************
** ng_parse definitions for the HCI node
***************************************************************************
***************************************************************************/
#ifndef _NETGRAPH_HCI_PRSE_H_
#define _NETGRAPH_HCI_PRSE_H_ 1
/* BDADDR */
static const struct ng_parse_fixedarray_info ng_hci_bdaddr_type_info = {
&ng_parse_uint8_type,
NG_HCI_BDADDR_SIZE
};
static const struct ng_parse_type ng_hci_bdaddr_type = {
&ng_parse_fixedarray_type,
&ng_hci_bdaddr_type_info
};
/* Features */
static const struct ng_parse_fixedarray_info ng_hci_features_type_info = {
&ng_parse_uint8_type,
NG_HCI_FEATURES_SIZE
};
static const struct ng_parse_type ng_hci_features_type = {
&ng_parse_fixedarray_type,
&ng_hci_features_type_info
};
/* Buffer info */
static const struct ng_parse_struct_field ng_hci_buffer_type_fields[] =
{
{ "cmd_free", &ng_parse_uint8_type, },
{ "sco_size", &ng_parse_uint8_type, },
{ "sco_pkts", &ng_parse_uint16_type, },
{ "sco_free", &ng_parse_uint16_type, },
{ "acl_size", &ng_parse_uint16_type, },
{ "acl_pkts", &ng_parse_uint16_type, },
{ "acl_free", &ng_parse_uint16_type, },
{ NULL, }
};
static const struct ng_parse_type ng_hci_buffer_type = {
&ng_parse_struct_type,
&ng_hci_buffer_type_fields
};
/* Stat info */
static const struct ng_parse_struct_field ng_hci_stat_type_fields[] =
{
{ "cmd_sent", &ng_parse_uint32_type, },
{ "evnt_recv", &ng_parse_uint32_type, },
{ "acl_recv", &ng_parse_uint32_type, },
{ "acl_sent", &ng_parse_uint32_type, },
{ "sco_recv", &ng_parse_uint32_type, },
{ "sco_sent", &ng_parse_uint32_type, },
{ "bytes_recv", &ng_parse_uint32_type, },
{ "bytes_sent", &ng_parse_uint32_type, },
{ NULL, }
};
static const struct ng_parse_type ng_hci_stat_type = {
&ng_parse_struct_type,
&ng_hci_stat_type_fields
};
/*
* HCI node command list
*/
static const struct ng_cmdlist ng_hci_cmdlist[] = {
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_STATE,
"get_state",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_INIT,
"init",
NULL,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_DEBUG,
"get_debug",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_SET_DEBUG,
"set_debug",
&ng_parse_uint16_type,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_BUFFER,
"get_buff_info",
NULL,
&ng_hci_buffer_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_BDADDR,
"get_bdaddr",
NULL,
&ng_hci_bdaddr_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_FEATURES,
"get_features",
NULL,
&ng_hci_features_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_STAT,
"get_stat",
NULL,
&ng_hci_stat_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_RESET_STAT,
"reset_stat",
NULL,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE,
"flush_ncache",
NULL,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK,
"get_lm_mask",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK,
"set_lm_mask",
&ng_parse_uint16_type,
NULL
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_GET_PACKET_MASK,
"get_pkt_mask",
NULL,
&ng_parse_uint16_type
},
{
NGM_HCI_COOKIE,
NGM_HCI_NODE_SET_PACKET_MASK,
"set_pkt_mask",
&ng_parse_uint16_type,
NULL
},
{ 0, }
};
#endif /* ndef _NETGRAPH_HCI_PRSE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
/*
* ng_hci_ulpi.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_hci_ulpi.h,v 1.4 2002/09/04 21:36:52 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_ULPI_H_
#define _NETGRAPH_HCI_ULPI_H_
/*
* LP_xxx event handlers
*/
int ng_hci_lp_con_req (ng_hci_unit_p, item_p, hook_p);
int ng_hci_lp_discon_req (ng_hci_unit_p, item_p, hook_p);
int ng_hci_lp_con_cfm (ng_hci_unit_con_p, int);
int ng_hci_lp_con_ind (ng_hci_unit_con_p, u_int8_t *);
int ng_hci_lp_con_rsp (ng_hci_unit_p, item_p, hook_p);
int ng_hci_lp_discon_ind (ng_hci_unit_con_p, int);
int ng_hci_lp_qos_req (ng_hci_unit_p, item_p, hook_p);
int ng_hci_lp_qos_cfm (ng_hci_unit_con_p, int);
int ng_hci_lp_qos_ind (ng_hci_unit_con_p);
void ng_hci_process_con_timeout (node_p, hook_p, void *, int);
void ng_hci_process_con_watchdog_timeout (node_p, hook_p, void *, int);
#endif /* ndef _NETGRAPH_HCI_ULPI_H_ */

View File

@ -0,0 +1,217 @@
/*
* ng_hci_var.h
*
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_hci_var.h,v 1.14 2002/11/12 22:35:40 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_HCI_VAR_H_
#define _NETGRAPH_HCI_VAR_H_ 1
/* MALLOC decalation */
#ifdef NG_SEPARATE_MALLOC
MALLOC_DECLARE(M_NETGRAPH_HCI);
#else
#define M_NETGRAPH_HCI M_NETGRAPH
#endif /* NG_SEPARATE_MALLOC */
/* Debug */
#define NG_HCI_ALERT if (unit->debug >= NG_HCI_ALERT_LEVEL) printf
#define NG_HCI_ERR if (unit->debug >= NG_HCI_ERR_LEVEL) printf
#define NG_HCI_WARN if (unit->debug >= NG_HCI_WARN_LEVEL) printf
#define NG_HCI_INFO if (unit->debug >= NG_HCI_INFO_LEVEL) printf
/* Wrapper around m_pullup */
#define NG_HCI_M_PULLUP(m, s) \
do { \
if ((m)->m_len < (s)) \
(m) = m_pullup((m), (s)); \
if ((m) == NULL) \
NG_HCI_ALERT("%s: %s - m_pullup(%d) failed\n", \
__func__, NG_NODE_NAME(unit->node), (s)); \
} while (0)
/*
* Unit hardware buffer descriptor
*/
typedef struct ng_hci_unit_buff {
u_int8_t cmd_free; /* space available (cmds) */
u_int8_t sco_size; /* max. size of one packet */
u_int16_t sco_pkts; /* size of buffer (packets) */
u_int16_t sco_free; /* space available (packets)*/
u_int16_t acl_size; /* max. size of one packet */
u_int16_t acl_pkts; /* size of buffer (packets) */
u_int16_t acl_free; /* space available (packets)*/
} ng_hci_unit_buff_t;
/*
* These macro's must be used everywhere in the code. So if extra locking
* is required later, it can be added without much troubles.
*/
#define NG_HCI_BUFF_CMD_SET(b, v) (b).cmd_free = (v)
#define NG_HCI_BUFF_CMD_GET(b, v) (v) = (b).cmd_free
#define NG_HCI_BUFF_CMD_USE(b, v) (b).cmd_free -= (v)
#define NG_HCI_BUFF_ACL_USE(b, v) (b).acl_free -= (v)
#define NG_HCI_BUFF_ACL_FREE(b, v) \
do { \
(b).acl_free += (v); \
if ((b).acl_free > (b).acl_pkts) \
(b).acl_free = (b).acl_pkts; \
} while (0)
#define NG_HCI_BUFF_ACL_AVAIL(b, v) (v) = (b).acl_free
#define NG_HCI_BUFF_ACL_TOTAL(b, v) (v) = (b).acl_pkts
#define NG_HCI_BUFF_ACL_SIZE(b, v) (v) = (b).acl_size
#define NG_HCI_BUFF_ACL_SET(b, n, s, f) \
do { \
(b).acl_free = (f); \
(b).acl_size = (s); \
(b).acl_pkts = (n); \
} while (0)
#define NG_HCI_BUFF_SCO_USE(b, v) (b).sco_free -= (v)
#define NG_HCI_BUFF_SCO_FREE(b, v) \
do { \
(b).sco_free += (v); \
if ((b).sco_free > (b).sco_pkts) \
(b).sco_free = (b).sco_pkts; \
} while (0)
#define NG_HCI_BUFF_SCO_AVAIL(b, v) (v) = (b).sco_free
#define NG_HCI_BUFF_SCO_TOTAL(b, v) (v) = (b).sco_pkts
#define NG_HCI_BUFF_SCO_SIZE(b, v) (v) = (b).sco_size
#define NG_HCI_BUFF_SCO_SET(b, n, s, f) \
do { \
(b).sco_free = (f); \
(b).sco_size = (s); \
(b).sco_pkts = (n); \
} while (0)
/*
* Unit (Node private)
*/
struct ng_hci_unit_con;
struct ng_hci_neighbor;
typedef struct ng_hci_unit {
node_p node; /* node ptr */
ng_hci_node_debug_ep debug; /* debug level */
ng_hci_node_state_ep state; /* unit state */
bdaddr_t bdaddr; /* unit address */
u_int8_t features[NG_HCI_FEATURES_SIZE];
/* LMP features */
ng_hci_node_link_policy_mask_ep link_policy_mask; /* link policy mask */
ng_hci_node_packet_mask_ep packet_mask; /* packet mask */
ng_hci_node_stat_ep stat; /* statistic */
#define NG_HCI_STAT_CMD_SENT(s) (s).cmd_sent ++
#define NG_HCI_STAT_EVNT_RECV(s) (s).evnt_recv ++
#define NG_HCI_STAT_ACL_SENT(s, n) (s).acl_sent += (n)
#define NG_HCI_STAT_ACL_RECV(s) (s).acl_recv ++
#define NG_HCI_STAT_SCO_SENT(s, n) (s).sco_sent += (n)
#define NG_HCI_STAT_SCO_RECV(s) (s).sco_recv ++
#define NG_HCI_STAT_BYTES_SENT(s, b) (s).bytes_sent += (b)
#define NG_HCI_STAT_BYTES_RECV(s, b) (s).bytes_recv += (b)
#define NG_HCI_STAT_RESET(s) bzero(&(s), sizeof((s)))
ng_hci_unit_buff_t buffer; /* buffer info */
struct callout_handle cmd_timo; /* command timeout */
ng_bt_mbufq_t cmdq; /* command queue */
#define NG_HCI_CMD_QUEUE_LEN 12 /* max. size of cmd q */
hook_p drv; /* driver hook */
hook_p acl; /* upstream hook */
hook_p sco; /* upstream hook */
hook_p raw; /* upstream hook */
LIST_HEAD(, ng_hci_unit_con) con_list; /* connections */
LIST_HEAD(, ng_hci_neighbor) neighbors; /* unit neighbors */
} ng_hci_unit_t;
typedef ng_hci_unit_t * ng_hci_unit_p;
/*
* Unit connection descriptor
*/
typedef struct ng_hci_unit_con {
ng_hci_unit_p unit; /* pointer back */
u_int16_t state; /* con. state */
u_int16_t flags; /* con. flags */
#define NG_HCI_CON_TIMEOUT_PENDING (1 << 0)
#define NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING (1 << 1)
#define NG_HCI_CON_NOTIFY_ACL (1 << 2)
#define NG_HCI_CON_NOTIFY_SCO (1 << 3)
bdaddr_t bdaddr; /* remote address */
u_int16_t con_handle; /* con. handle */
u_int8_t link_type; /* ACL or SCO */
u_int8_t encryption_mode; /* none, p2p, ... */
u_int8_t mode; /* ACTIVE, HOLD ... */
u_int8_t role; /* MASTER/SLAVE */
struct callout_handle con_timo; /* con. timeout */
struct callout_handle watchdog_timo; /* watch dog */
int pending; /* # of data pkts */
ng_bt_itemq_t conq; /* con. queue */
LIST_ENTRY(ng_hci_unit_con) next; /* next */
} ng_hci_unit_con_t;
typedef ng_hci_unit_con_t * ng_hci_unit_con_p;
/*
* Unit's neighbor descriptor.
* Neighbor is a remote unit that responded to our inquiry.
*/
typedef struct ng_hci_neighbor {
struct timeval updated; /* entry was updated */
bdaddr_t bdaddr; /* address */
u_int8_t features[NG_HCI_FEATURES_SIZE];
/* LMP features */
u_int8_t page_scan_rep_mode; /* PS rep. mode */
u_int8_t page_scan_mode; /* page scan mode */
u_int16_t clock_offset; /* clock offset */
LIST_ENTRY(ng_hci_neighbor) next;
} ng_hci_neighbor_t;
typedef ng_hci_neighbor_t * ng_hci_neighbor_p;
#endif /* ndef _NETGRAPH_HCI_VAR_H_ */

View File

@ -0,0 +1,232 @@
/*
* bluetooth.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_bluetooth.h,v 1.1.1.1 2002/09/04 21:47:41 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BLUETOOTH_H_
#define _NETGRAPH_BLUETOOTH_H_ 1
/*
* Version of the stack
*/
#define NG_BLUETOOTH_VERSION 1
/*
* Declare the base of the Bluetooth sysctl hierarchy,
* but only if this file cares about sysctl's
*/
#ifdef SYSCTL_DECL
SYSCTL_DECL(_net_bluetooth);
SYSCTL_DECL(_net_bluetooth_hci);
SYSCTL_DECL(_net_bluetooth_l2cap);
#endif /* SYSCTL_DECL */
/*
* Mbuf qeueue and useful mbufq macros. We do not use ifqueue because we
* do not need mutex and other locking stuff
*/
struct mbuf;
struct ng_bt_mbufq {
struct mbuf *head; /* first item in the queue */
struct mbuf *tail; /* last item in the queue */
u_int32_t len; /* number of items in the queue */
u_int32_t maxlen; /* maximal number of items in the queue */
u_int32_t drops; /* number if dropped items */
};
typedef struct ng_bt_mbufq ng_bt_mbufq_t;
typedef struct ng_bt_mbufq * ng_bt_mbufq_p;
#define NG_BT_MBUFQ_INIT(q, _maxlen) \
do { \
(q)->head = NULL; \
(q)->tail = NULL; \
(q)->len = 0; \
(q)->maxlen = (_maxlen); \
(q)->drops = 0; \
} while (0)
#define NG_BT_MBUFQ_DESTROY(q) \
do { \
NG_BT_MBUFQ_DRAIN((q)); \
} while (0)
#define NG_BT_MBUFQ_FIRST(q) (q)->head
#define NG_BT_MBUFQ_LEN(q) (q)->len
#define NG_BT_MBUFQ_FULL(q) (q)->len >= (q)->maxlen
#define NG_BT_MBUFQ_DROP(q) (q)->drops ++
#define NG_BT_MBUFQ_ENQUEUE(q, i) \
do { \
(i)->m_nextpkt = NULL; \
\
if ((q)->tail == NULL) \
(q)->head = (i); \
else \
(q)->tail->m_nextpkt = (i); \
\
(q)->tail = (i); \
(q)->len ++; \
} while (0)
#define NG_BT_MBUFQ_DEQUEUE(q, i) \
do { \
(i) = (q)->head; \
if ((i) != NULL) { \
(q)->head = (q)->head->m_nextpkt; \
if ((q)->head == NULL) \
(q)->tail = NULL; \
\
(q)->len --; \
(i)->m_nextpkt = NULL; \
} \
} while (0)
#define NG_BT_MBUFQ_PREPEND(q, i) \
do { \
(i)->m_nextpkt = (q)->head; \
if ((q)->tail == NULL) \
(q)->tail = (i); \
\
(q)->head = (i); \
(q)->len ++; \
} while (0)
#define NG_BT_MBUFQ_DRAIN(q) \
do { \
struct mbuf *m = NULL; \
\
for (;;) { \
NG_BT_MBUFQ_DEQUEUE((q), m); \
if (m == NULL) \
break; \
\
NG_FREE_M(m); \
} \
} while (0)
/*
* Netgraph item queue and useful itemq macros
*/
struct ng_item;
struct ng_bt_itemq {
struct ng_item *head; /* first item in the queue */
struct ng_item *tail; /* last item in the queue */
u_int32_t len; /* number of items in the queue */
u_int32_t maxlen; /* maximal number of items in the queue */
u_int32_t drops; /* number if dropped items */
};
typedef struct ng_bt_itemq ng_bt_itemq_t;
typedef struct ng_bt_itemq * ng_bt_itemq_p;
#define NG_BT_ITEMQ_INIT(q, _maxlen) NG_BT_MBUFQ_INIT((q), (_maxlen))
#define NG_BT_ITEMQ_DESTROY(q) \
do { \
NG_BT_ITEMQ_DRAIN((q)); \
} while (0)
#define NG_BT_ITEMQ_FIRST(q) NG_BT_MBUFQ_FIRST((q))
#define NG_BT_ITEMQ_LEN(q) NG_BT_MBUFQ_LEN((q))
#define NG_BT_ITEMQ_FULL(q) NG_BT_MBUFQ_FULL((q))
#define NG_BT_ITEMQ_DROP(q) NG_BT_MBUFQ_DROP((q))
#define NG_BT_ITEMQ_ENQUEUE(q, i) \
do { \
(i)->el_next = NULL; \
\
if ((q)->tail == NULL) \
(q)->head = (i); \
else \
(q)->tail->el_next = (i); \
\
(q)->tail = (i); \
(q)->len ++; \
} while (0)
#define NG_BT_ITEMQ_DEQUEUE(q, i) \
do { \
(i) = (q)->head; \
if ((i) != NULL) { \
(q)->head = (q)->head->el_next; \
if ((q)->head == NULL) \
(q)->tail = NULL; \
\
(q)->len --; \
(i)->el_next = NULL; \
} \
} while (0)
#define NG_BT_ITEMQ_PREPEND(q, i) \
do { \
(i)->el_next = (q)->head; \
if ((q)->tail == NULL) \
(q)->tail = (i); \
\
(q)->head = (i); \
(q)->len ++; \
} while (0)
#define NG_BT_ITEMQ_DRAIN(q) \
do { \
struct ng_item *i = NULL; \
\
for (;;) { \
NG_BT_ITEMQ_DEQUEUE((q), i); \
if (i == NULL) \
break; \
\
NG_FREE_ITEM(i); \
} \
} while (0)
/*
* Get Bluetooth stack sysctl globals
*/
u_int32_t bluetooth_hci_command_timeout (void);
u_int32_t bluetooth_hci_connect_timeout (void);
u_int32_t bluetooth_hci_watchdog_timeout (void);
u_int32_t bluetooth_hci_max_neighbor_age (void);
u_int32_t bluetooth_l2cap_rtx_timeout (void);
u_int32_t bluetooth_l2cap_ertx_timeout (void);
#endif /* _NETGRAPH_BLUETOOTH_H_ */

View File

@ -0,0 +1,114 @@
/*
* ng_bt3c.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_bt3c.h,v 1.2 2002/11/12 00:51:45 max Exp $
* $FreeBSD$
*
* XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*
* Based on information obrained from: Jose Orlando Pereira <jop@di.uminho.pt>
* and disassembled w2k driver.
*
* XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*
*/
#ifndef _NG_BT3C_H_
#define _NG_BT3C_H_
/* XXX FIME: does not belong here. Move to pccarddevs.h later */
#define PCMCIA_PRODUCT_3COM_3CRWB609 0x0040
#define PCMCIA_STR_3COM_3CRWB609 "3Com Bluetooth PC Card 3CRWB60-A"
#define PCMCIA_CIS_3COM_3CRWB609 { NULL, NULL, NULL, NULL }
/**************************************************************************
**************************************************************************
** Netgraph node hook name, type name and type cookie and commands
**************************************************************************
**************************************************************************/
#define NG_BT3C_NODE_TYPE "btccc" /* XXX can't use bt3c in pccard.conf */
#define NG_BT3C_HOOK "hook"
#define NGM_BT3C_COOKIE 1014752016
/* Debug levels */
#define NG_BT3C_ALERT_LEVEL 1
#define NG_BT3C_ERR_LEVEL 2
#define NG_BT3C_WARN_LEVEL 3
#define NG_BT3C_INFO_LEVEL 4
/* Node states */
#define NG_BT3C_W4_PKT_IND 1 /* wait for packet indicator */
#define NG_BT3C_W4_PKT_HDR 2 /* wait for packet header */
#define NG_BT3C_W4_PKT_DATA 3 /* wait for packet data */
/**************************************************************************
**************************************************************************
** BT3C node command/event parameters
**************************************************************************
**************************************************************************/
#define NGM_BT3C_NODE_GET_STATE 1 /* get node state */
typedef u_int16_t ng_bt3c_node_state_ep;
#define NGM_BT3C_NODE_SET_DEBUG 2 /* set debug level */
#define NGM_BT3C_NODE_GET_DEBUG 3 /* get debug level */
typedef u_int16_t ng_bt3c_node_debug_ep;
#define NGM_BT3C_NODE_GET_QLEN 4 /* get queue length */
#define NGM_BT3C_NODE_SET_QLEN 5 /* set queue length */
typedef struct {
int32_t queue; /* queue index */
#define NGM_BT3C_NODE_IN_QUEUE 1 /* incoming queue */
#define NGM_BT3C_NODE_OUT_QUEUE 2 /* outgoing queue */
int32_t qlen; /* queue length */
} ng_bt3c_node_qlen_ep;
#define NGM_BT3C_NODE_GET_STAT 6 /* get statistic */
typedef struct {
u_int32_t pckts_recv; /* # of packets received */
u_int32_t bytes_recv; /* # of bytes received */
u_int32_t pckts_sent; /* # of packets sent */
u_int32_t bytes_sent; /* # of bytes sent */
u_int32_t oerrors; /* # of output errors */
u_int32_t ierrors; /* # of input errors */
} ng_bt3c_node_stat_ep;
#define NGM_BT3C_NODE_RESET_STAT 7 /* reset statistic */
#define NGM_BT3C_NODE_DOWNLOAD_FIRMWARE 8 /* download firmware */
typedef struct {
u_int32_t block_address;
u_int16_t block_size; /* in words */
u_int16_t block_alignment; /* in bytes */
} ng_bt3c_firmware_block_ep;
#endif /* ndef _NG_BT3C_H_ */

View File

@ -0,0 +1,319 @@
/*
* ng_btsocket.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_btsocket.h,v 1.7 2002/11/12 22:31:39 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BTSOCKET_H_
#define _NETGRAPH_BTSOCKET_H_ 1
/*
* XXX FIXME: does not belong here, move to sys/socket.h later and fix AF_MAX
*/
#define AF_BLUETOOTH 36 /* Address family */
#define PF_BLUETOOTH AF_BLUETOOTH /* Protocol family */
/*
* XXX FIXME: does not belong here, move to other places later
*/
#define BLUETOOTH_PROTO_HCI 134 /* HCI protocol number */
#define BLUETOOTH_PROTO_L2CAP 135 /* L2CAP protocol number */
/*
* XXX FIXME: probably does not belong here
* Bluetooth version of struct sockaddr for raw HCI sockets
*/
struct sockaddr_hci {
u_char hci_len; /* total length */
u_char hci_family; /* address family */
char hci_node[16]; /* address (size == NG_NODELEN + 1) */
};
/* Raw HCI socket options */
#define SOL_HCI_RAW 0x0802 /* socket options level */
#define SO_HCI_RAW_FILTER 1 /* get/set filter on socket */
#define SO_HCI_RAW_DIRECTION 2 /* turn on/off direction info */
#define SCM_HCI_RAW_DIRECTION SO_HCI_RAW_DIRECTION /* cmsg_type */
/*
* Raw HCI socket filter.
*
* For packet mask use (1 << (HCI packet indicator - 1))
* For event mask use (1 << (Event - 1))
*/
struct ng_btsocket_hci_raw_filter {
bitstr_t bit_decl(packet_mask, 32);
bitstr_t bit_decl(event_mask, (NG_HCI_EVENT_MASK_SIZE * 8));
};
/*
* Raw HCI sockets ioctl's
*/
/* Get state */
struct ng_btsocket_hci_raw_node_state {
char hci_node[16];
ng_hci_node_state_ep state;
};
#define SIOC_HCI_RAW_NODE_GET_STATE \
_IOWR('b', NGM_HCI_NODE_GET_STATE, \
struct ng_btsocket_hci_raw_node_state)
/* Initialize */
struct ng_btsocket_hci_raw_node_init {
char hci_node[16];
};
#define SIOC_HCI_RAW_NODE_INIT \
_IOWR('b', NGM_HCI_NODE_INIT, \
struct ng_btsocket_hci_raw_node_init)
/* Get/Set debug level */
struct ng_btsocket_hci_raw_node_debug {
char hci_node[16];
ng_hci_node_debug_ep debug;
};
#define SIOC_HCI_RAW_NODE_GET_DEBUG \
_IOWR('b', NGM_HCI_NODE_GET_DEBUG, \
struct ng_btsocket_hci_raw_node_debug)
#define SIOC_HCI_RAW_NODE_SET_DEBUG \
_IOWR('b', NGM_HCI_NODE_SET_DEBUG, \
struct ng_btsocket_hci_raw_node_debug)
/* Get buffer info */
struct ng_btsocket_hci_raw_node_buffer {
char hci_node[16];
ng_hci_node_buffer_ep buffer;
};
#define SIOC_HCI_RAW_NODE_GET_BUFFER \
_IOWR('b', NGM_HCI_NODE_GET_BUFFER, \
struct ng_btsocket_hci_raw_node_buffer)
/* Get BD_ADDR */
struct ng_btsocket_hci_raw_node_bdaddr {
char hci_node[16];
bdaddr_t bdaddr;
};
#define SIOC_HCI_RAW_NODE_GET_BDADDR \
_IOWR('b', NGM_HCI_NODE_GET_BDADDR, \
struct ng_btsocket_hci_raw_node_bdaddr)
/* Get features */
struct ng_btsocket_hci_raw_node_features {
char hci_node [16];
u_int8_t features[NG_HCI_FEATURES_SIZE];
};
#define SIOC_HCI_RAW_NODE_GET_FEATURES \
_IOWR('b', NGM_HCI_NODE_GET_FEATURES, \
struct ng_btsocket_hci_raw_node_features)
/* Get stat */
struct ng_btsocket_hci_raw_node_stat {
char hci_node[16];
ng_hci_node_stat_ep stat;
};
#define SIOC_HCI_RAW_NODE_GET_STAT \
_IOWR('b', NGM_HCI_NODE_GET_STAT, \
struct ng_btsocket_hci_raw_node_stat)
/* Reset stat */
struct ng_btsocket_hci_raw_node_reset_stat {
char hci_node[16];
};
#define SIOC_HCI_RAW_NODE_RESET_STAT \
_IOWR('b', NGM_HCI_NODE_RESET_STAT, \
struct ng_btsocket_hci_raw_node_reset_stat)
/* Flush neighbor cache */
struct ng_btsocket_hci_raw_node_flush_neighbor_cache {
char hci_node[16];
};
#define SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE \
_IOWR('b', NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE, \
struct ng_btsocket_hci_raw_node_flush_neighbor_cache)
/* Get neighbor cache */
struct ng_btsocket_hci_raw_node_neighbor_cache {
char hci_node[16];
u_int32_t num_entries;
ng_hci_node_neighbor_cache_entry_ep *entries;
};
#define SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE \
_IOWR('b', NGM_HCI_NODE_GET_NEIGHBOR_CACHE, \
struct ng_btsocket_hci_raw_node_neighbor_cache)
/* Get connection list */
struct ng_btsocket_hci_raw_con_list {
char hci_node[16];
u_int32_t num_connections;
ng_hci_node_con_ep *connections;
};
#define SIOC_HCI_RAW_NODE_GET_CON_LIST \
_IOWR('b', NGM_HCI_NODE_GET_CON_LIST, \
struct ng_btsocket_hci_raw_con_list)
/* Get/Set link policy settings mask */
struct ng_btsocket_hci_raw_node_link_policy_mask {
char hci_node[16];
ng_hci_node_link_policy_mask_ep policy_mask;
};
#define SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK \
_IOWR('b', NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK, \
struct ng_btsocket_hci_raw_node_link_policy_mask)
#define SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK \
_IOWR('b', NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK, \
struct ng_btsocket_hci_raw_node_link_policy_mask)
/* Get/Set packet mask */
struct ng_btsocket_hci_raw_node_packet_mask {
char hci_node[16];
ng_hci_node_packet_mask_ep packet_mask;
};
#define SIOC_HCI_RAW_NODE_GET_PACKET_MASK \
_IOWR('b', NGM_HCI_NODE_GET_PACKET_MASK, \
struct ng_btsocket_hci_raw_node_packet_mask)
#define SIOC_HCI_RAW_NODE_SET_PACKET_MASK \
_IOWR('b', NGM_HCI_NODE_SET_PACKET_MASK, \
struct ng_btsocket_hci_raw_node_packet_mask)
/*
* XXX FIXME: probably does not belong here
* Bluetooth version of struct sockaddr for L2CAP sockets (RAW and SEQPACKET)
*/
struct sockaddr_l2cap {
u_char l2cap_len; /* total length */
u_char l2cap_family; /* address family */
u_int16_t l2cap_psm; /* PSM (Protocol/Service Multiplexor) */
bdaddr_t l2cap_bdaddr; /* address */
};
/* L2CAP socket options */
#define SOL_L2CAP 0x1609 /* socket option level */
#define SO_L2CAP_IMTU 1 /* get/set incoming MTU */
#define SO_L2CAP_OMTU 2 /* get outgoing (peer incoming) MTU */
#define SO_L2CAP_IFLOW 3 /* get incoming flow spec. */
#define SO_L2CAP_OFLOW 4 /* get/set outgoing flow spec. */
#define SO_L2CAP_FLUSH 5 /* get/set flush timeout */
/*
* Raw L2CAP sockets ioctl's
*/
/* Ping */
struct ng_btsocket_l2cap_raw_ping {
bdaddr_t bdaddr[2];
#define echo_src bdaddr[0]
#define echo_dst bdaddr[1]
u_int32_t result;
u_int32_t echo_size;
u_int8_t *echo_data;
};
#define SIOC_L2CAP_L2CA_PING \
_IOWR('b', NGM_L2CAP_L2CA_PING, \
struct ng_btsocket_l2cap_raw_ping)
/* Get info */
struct ng_btsocket_l2cap_raw_get_info {
bdaddr_t bdaddr[2];
#define info_src bdaddr[0]
#define info_dst bdaddr[1]
u_int32_t result;
u_int32_t info_type;
u_int32_t info_size;
u_int8_t *info_data;
};
#define SIOC_L2CAP_L2CA_GET_INFO \
_IOWR('b', NGM_L2CAP_L2CA_GET_INFO, \
struct ng_btsocket_l2cap_raw_get_info)
/* Get flags */
struct ng_btsocket_l2cap_raw_node_flags {
bdaddr_t src;
ng_l2cap_node_flags_ep flags;
};
#define SIOC_L2CAP_NODE_GET_FLAGS \
_IOWR('b', NGM_L2CAP_NODE_GET_FLAGS, \
struct ng_btsocket_l2cap_raw_node_flags)
/* Get/Set debug level */
struct ng_btsocket_l2cap_raw_node_debug {
bdaddr_t src;
ng_l2cap_node_debug_ep debug;
};
#define SIOC_L2CAP_NODE_GET_DEBUG \
_IOWR('b', NGM_L2CAP_NODE_GET_DEBUG, \
struct ng_btsocket_l2cap_raw_node_debug)
#define SIOC_L2CAP_NODE_SET_DEBUG \
_IOWR('b', NGM_L2CAP_NODE_SET_DEBUG, \
struct ng_btsocket_l2cap_raw_node_debug)
/* Get connection list */
struct ng_btsocket_l2cap_raw_con_list {
bdaddr_t src;
u_int32_t num_connections;
ng_l2cap_node_con_ep *connections;
};
#define SIOC_L2CAP_NODE_GET_CON_LIST \
_IOWR('b', NGM_L2CAP_NODE_GET_CON_LIST, \
struct ng_btsocket_l2cap_raw_con_list)
/* Get channel list */
struct ng_btsocket_l2cap_raw_chan_list {
bdaddr_t src;
u_int32_t num_channels;
ng_l2cap_node_chan_ep *channels;
};
#define SIOC_L2CAP_NODE_GET_CHAN_LIST \
_IOWR('b', NGM_L2CAP_NODE_GET_CHAN_LIST, \
struct ng_btsocket_l2cap_raw_chan_list)
/*
* Netgraph node type name and cookie
*/
#define NG_BTSOCKET_HCI_RAW_NODE_TYPE "btsock_hci_raw"
#define NG_BTSOCKET_L2CAP_RAW_NODE_TYPE "btsock_l2c_raw"
#define NG_BTSOCKET_L2CAP_NODE_TYPE "btsock_l2c"
/*
* Debug levels
*/
#define NG_BTSOCKET_ALERT_LEVEL 1
#define NG_BTSOCKET_ERR_LEVEL 2
#define NG_BTSOCKET_WARN_LEVEL 3
#define NG_BTSOCKET_INFO_LEVEL 4
#endif /* _NETGRAPH_BTSOCKET_H_ */

View File

@ -0,0 +1,85 @@
/*
* ng_btsocket_hci_raw.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_btsocket_hci_raw.h,v 1.2 2002/09/16 19:46:02 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BTSOCKET_HCI_RAW_H_
#define _NETGRAPH_BTSOCKET_HCI_RAW_H_ 1
#define NG_BTSOCKET_HCI_RAW_SENDSPACE (4 * 1024)
#define NG_BTSOCKET_HCI_RAW_RECVSPACE (4 * 1024)
/*
* Bluetooth raw HCI socket PCB
*/
struct ng_btsocket_hci_raw_pcb {
struct socket *so; /* socket */
int flags; /* flags */
#define NG_BTSOCKET_HCI_RAW_DIRECTION (1 << 0)
struct sockaddr_hci addr; /* local address */
struct ng_btsocket_hci_raw_filter filter; /* filter */
u_int32_t token; /* message token */
struct ng_mesg *msg; /* message */
LIST_ENTRY(ng_btsocket_hci_raw_pcb) next; /* link to next */
};
typedef struct ng_btsocket_hci_raw_pcb ng_btsocket_hci_raw_pcb_t;
typedef struct ng_btsocket_hci_raw_pcb * ng_btsocket_hci_raw_pcb_p;
#define so2hci_raw_pcb(so) \
((struct ng_btsocket_hci_raw_pcb *)((so)->so_pcb))
/*
* Bluetooth raw HCI socket methods
*/
#ifdef _KERNEL
void ng_btsocket_hci_raw_init (void);
int ng_btsocket_hci_raw_abort (struct socket *);
int ng_btsocket_hci_raw_attach (struct socket *, int, struct thread *);
int ng_btsocket_hci_raw_bind (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_hci_raw_connect (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_hci_raw_control (struct socket *, u_long, caddr_t,
struct ifnet *, struct thread *);
int ng_btsocket_hci_raw_ctloutput (struct socket *, struct sockopt *);
int ng_btsocket_hci_raw_detach (struct socket *);
int ng_btsocket_hci_raw_disconnect (struct socket *);
int ng_btsocket_hci_raw_peeraddr (struct socket *, struct sockaddr **);
int ng_btsocket_hci_raw_send (struct socket *, int, struct mbuf *,
struct sockaddr *, struct mbuf *,
struct thread *);
int ng_btsocket_hci_raw_sockaddr (struct socket *, struct sockaddr **);
#endif /* _KERNEL */
#endif /* ndef _NETGRAPH_BTSOCKET_HCI_RAW_H_ */

View File

@ -0,0 +1,200 @@
/*
* ng_btsocket_l2cap.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_btsocket_l2cap.h,v 1.3 2002/09/22 18:23:31 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_BTSOCKET_L2CAP_H_
#define _NETGRAPH_BTSOCKET_L2CAP_H_ 1
/*
* L2CAP routing entry
*/
struct ng_hook;
struct ng_message;
struct ng_btsocket_l2cap_rtentry {
bdaddr_t src; /* source BD_ADDR */
struct ng_hook *hook; /* downstream hook */
LIST_ENTRY(ng_btsocket_l2cap_rtentry) next; /* linkt to next */
};
typedef struct ng_btsocket_l2cap_rtentry ng_btsocket_l2cap_rtentry_t;
typedef struct ng_btsocket_l2cap_rtentry * ng_btsocket_l2cap_rtentry_p;
/*****************************************************************************
*****************************************************************************
** SOCK_RAW L2CAP sockets **
*****************************************************************************
*****************************************************************************/
#define NG_BTSOCKET_L2CAP_RAW_SENDSPACE NG_L2CAP_MTU_DEFAULT
#define NG_BTSOCKET_L2CAP_RAW_RECVSPACE NG_L2CAP_MTU_DEFAULT
/*
* Bluetooth raw L2CAP socket PCB
*/
struct ng_btsocket_l2cap_raw_pcb {
struct socket *so; /* socket */
bdaddr_t src; /* source address */
ng_btsocket_l2cap_rtentry_p rt; /* routing info */
u_int32_t token; /* message token */
struct ng_mesg *msg; /* message */
LIST_ENTRY(ng_btsocket_l2cap_raw_pcb) next; /* link to next PCB */
};
typedef struct ng_btsocket_l2cap_raw_pcb ng_btsocket_l2cap_raw_pcb_t;
typedef struct ng_btsocket_l2cap_raw_pcb * ng_btsocket_l2cap_raw_pcb_p;
#define so2l2cap_raw_pcb(so) \
((struct ng_btsocket_l2cap_raw_pcb *)((so)->so_pcb))
/*
* Bluetooth raw L2CAP socket methods
*/
#ifdef _KERNEL
void ng_btsocket_l2cap_raw_init (void);
int ng_btsocket_l2cap_raw_abort (struct socket *);
int ng_btsocket_l2cap_raw_attach (struct socket *, int, struct thread *);
int ng_btsocket_l2cap_raw_bind (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_l2cap_raw_connect (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_l2cap_raw_control (struct socket *, u_long, caddr_t,
struct ifnet *, struct thread *);
int ng_btsocket_l2cap_raw_detach (struct socket *);
int ng_btsocket_l2cap_raw_disconnect (struct socket *);
int ng_btsocket_l2cap_raw_peeraddr (struct socket *, struct sockaddr **);
int ng_btsocket_l2cap_raw_send (struct socket *, int, struct mbuf *,
struct sockaddr *, struct mbuf *,
struct thread *);
int ng_btsocket_l2cap_raw_sockaddr (struct socket *, struct sockaddr **);
#endif /* _KERNEL */
/*****************************************************************************
*****************************************************************************
** SOCK_SEQPACKET L2CAP sockets **
*****************************************************************************
*****************************************************************************/
#define NG_BTSOCKET_L2CAP_SENDSPACE NG_L2CAP_MTU_DEFAULT /* (64 * 1024) */
#define NG_BTSOCKET_L2CAP_RECVSPACE (64 * 1024)
/*
* Bluetooth L2CAP socket PCB
*/
struct ng_btsocket_l2cap_pcb {
struct socket *so; /* Pointer to socket */
bdaddr_t src; /* Source address */
bdaddr_t dst; /* Destination address */
u_int16_t psm; /* PSM */
u_int16_t cid; /* Local channel ID */
u_int16_t flags; /* socket flags */
#define NG_BTSOCKET_L2CAP_CLIENT (1 << 0) /* socket is client */
#define NG_BTSOCKET_L2CAP_TIMO (1 << 1) /* timeout pending */
u_int8_t state; /* socket state */
#define NG_BTSOCKET_L2CAP_CLOSED 0 /* socket closed */
#define NG_BTSOCKET_L2CAP_CONNECTING 1 /* wait for connect */
#define NG_BTSOCKET_L2CAP_CONFIGURING 2 /* wait for config */
#define NG_BTSOCKET_L2CAP_OPEN 3 /* socket open */
#define NG_BTSOCKET_L2CAP_DISCONNECTING 4 /* wait for disconnect */
u_int8_t cfg_state; /* config state */
#define NG_BTSOCKET_L2CAP_CFG_IN (1 << 0) /* incoming path done */
#define NG_BTSOCKET_L2CAP_CFG_OUT (1 << 1) /* outgoing path done */
#define NG_BTSOCKET_L2CAP_CFG_BOTH \
(NG_BTSOCKET_L2CAP_CFG_IN | NG_BTSOCKET_L2CAP_CFG_OUT)
#define NG_BTSOCKET_L2CAP_CFG_IN_SENT (1 << 2) /* L2CAP ConfigReq sent */
#define NG_BTSOCKET_L2CAP_CFG_OUT_SENT (1 << 3) /* ---/--- */
u_int16_t imtu; /* Incoming MTU */
ng_l2cap_flow_t iflow; /* Input flow spec */
u_int16_t omtu; /* Outgoing MTU */
ng_l2cap_flow_t oflow; /* Outgoing flow spec */
u_int16_t flush_timo; /* flush timeout */
u_int16_t link_timo; /* link timeout */
struct callout_handle timo; /* timeout */
u_int32_t token; /* message token */
ng_btsocket_l2cap_rtentry_p rt; /* routing info */
struct mtx pcb_mtx; /* pcb mutex */
LIST_ENTRY(ng_btsocket_l2cap_pcb) next; /* link to next PCB */
};
typedef struct ng_btsocket_l2cap_pcb ng_btsocket_l2cap_pcb_t;
typedef struct ng_btsocket_l2cap_pcb * ng_btsocket_l2cap_pcb_p;
#define so2l2cap_pcb(so) \
((struct ng_btsocket_l2cap_pcb *)((so)->so_pcb))
/*
* Bluetooth L2CAP socket methods
*/
#ifdef _KERNEL
void ng_btsocket_l2cap_init (void);
int ng_btsocket_l2cap_abort (struct socket *);
int ng_btsocket_l2cap_accept (struct socket *, struct sockaddr **);
int ng_btsocket_l2cap_attach (struct socket *, int, struct thread *);
int ng_btsocket_l2cap_bind (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_l2cap_connect (struct socket *, struct sockaddr *,
struct thread *);
int ng_btsocket_l2cap_control (struct socket *, u_long, caddr_t,
struct ifnet *, struct thread *);
int ng_btsocket_l2cap_ctloutput (struct socket *, struct sockopt *);
int ng_btsocket_l2cap_detach (struct socket *);
int ng_btsocket_l2cap_disconnect (struct socket *);
int ng_btsocket_l2cap_listen (struct socket *, struct thread *);
int ng_btsocket_l2cap_peeraddr (struct socket *, struct sockaddr **);
int ng_btsocket_l2cap_send (struct socket *, int, struct mbuf *,
struct sockaddr *, struct mbuf *,
struct thread *);
int ng_btsocket_l2cap_sockaddr (struct socket *, struct sockaddr **);
#endif /* _KERNEL */
#endif /* _NETGRAPH_BTSOCKET_L2CAP_H_ */

View File

@ -0,0 +1,118 @@
/*
* ng_h4.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_h4.h,v 1.5 2002/06/27 09:50:18 max Exp $
* $FreeBSD$
*
* Based on:
* ---------
*
* FreeBSD: src/sys/netgraph/ng_tty.h
* Author: Archie Cobbs <archie@freebsd.org>
*/
/*
* This file contains everything that application needs to know about
* Bluetooth HCI UART transport layer as per chapter H4 of the Bluetooth
* Specification Book v1.1.
*
* This file can be included by both kernel and userland applications.
*/
#ifndef _NETGRAPH_H4_H_
#define _NETGRAPH_H4_H_ 1
/*
* H4 line discipline
* XXX FIXME: does not belong here. Move to "ttycom.h" later
*/
#define H4DISC 7
/**************************************************************************
**************************************************************************
** Netgraph node hook name, type name and type cookie and commands
**************************************************************************
**************************************************************************/
/* Hook name */
#define NG_H4_HOOK "hook"
/* Node type name and magic cookie */
#define NG_H4_NODE_TYPE "h4"
#define NGM_H4_COOKIE 1013899512
/* Node states */
#define NG_H4_W4_PKT_IND 1 /* Waiting for packet indicator */
#define NG_H4_W4_PKT_HDR 2 /* Waiting for packet header */
#define NG_H4_W4_PKT_DATA 3 /* Waiting for packet data */
/* Debug levels */
#define NG_H4_ALERT_LEVEL 1
#define NG_H4_ERR_LEVEL 2
#define NG_H4_WARN_LEVEL 3
#define NG_H4_INFO_LEVEL 4
/**************************************************************************
**************************************************************************
** H4 node command/event parameters
**************************************************************************
**************************************************************************/
/* Reset node */
#define NGM_H4_NODE_RESET 1
/* Get node state (see states above) */
#define NGM_H4_NODE_GET_STATE 2
typedef u_int16_t ng_h4_node_state_ep;
/* Get/Set node debug level (see levels above) */
#define NGM_H4_NODE_GET_DEBUG 3
#define NGM_H4_NODE_SET_DEBUG 4
typedef u_int16_t ng_h4_node_debug_ep;
/* Get/Set max queue length for the node */
#define NGM_H4_NODE_GET_QLEN 5
#define NGM_H4_NODE_SET_QLEN 6
typedef int32_t ng_h4_node_qlen_ep;
/* Get node statistic */
#define NGM_H4_NODE_GET_STAT 7
typedef struct {
u_int32_t pckts_recv; /* # of packets received */
u_int32_t bytes_recv; /* # of bytes received */
u_int32_t pckts_sent; /* # of packets sent */
u_int32_t bytes_sent; /* # of bytes sent */
u_int32_t oerrors; /* # of output errors */
u_int32_t ierrors; /* # of input errors */
} ng_h4_node_stat_ep;
/* Reset node statistic */
#define NGM_H4_NODE_RESET_STAT 8
#endif /* _NETGRAPH_H4_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,655 @@
/*
* ng_l2cap.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap.h,v 1.13 2002/09/08 23:35:51 max Exp $
* $FreeBSD$
*/
/*
* This file contains everything that application needs to know about
* Link Layer Control and Adaptation Protocol (L2CAP). All information
* was obtained from Bluetooth Specification Book v1.1.
*
* This file can be included by both kernel and userland applications.
*/
#ifndef _NETGRAPH_L2CAP_H_
#define _NETGRAPH_L2CAP_H_
/**************************************************************************
**************************************************************************
** Netgraph node hook name, type name and type cookie and commands
**************************************************************************
**************************************************************************/
/* Netgraph node hook names */
#define NG_L2CAP_HOOK_HCI "hci" /* HCI <-> L2CAP */
#define NG_L2CAP_HOOK_L2C "l2c" /* L2CAP <-> Upper */
#define NG_L2CAP_HOOK_CTL "ctl" /* L2CAP <-> User */
/* Node type name and type cookie */
#define NG_L2CAP_NODE_TYPE "l2cap"
#define NGM_L2CAP_COOKIE 1000774185
/**************************************************************************
**************************************************************************
** Common defines and types (L2CAP)
**************************************************************************
**************************************************************************/
/*
* Channel IDs are assigned relative to the instance of L2CAP node, i.e.
* relative to the unit. So the total number of channels that unit can have
* open at the same time is 0xffff - 0x0040 = 0xffbf (65471). This number
* does not depend on number of connections.
*/
#define NG_L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */
#define NG_L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */
#define NG_L2CAP_CLT_CID 0x0002 /* connectionless channel ID */
/* 0x0003 - 0x003f Reserved */
#define NG_L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */
#define NG_L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */
/* L2CAP MTU */
#define NG_L2CAP_MTU_MINIMUM 48
#define NG_L2CAP_MTU_DEFAULT 672
#define NG_L2CAP_MTU_MAXIMUM 0xffff
/* L2CAP flush and link timeouts */
#define NG_L2CAP_FLUSH_TIMO_DEFAULT 0xffff /* always retransmit */
#define NG_L2CAP_LINK_TIMO_DEFAULT 0xffff
/* L2CAP Command Reject reasons */
#define NG_L2CAP_REJ_NOT_UNDERSTOOD 0x0000
#define NG_L2CAP_REJ_MTU_EXCEEDED 0x0001
#define NG_L2CAP_REJ_INVALID_CID 0x0002
/* 0x0003 - 0xffff - reserved for future use */
/* Protocol/Service Multioplexor (PSM) values */
#define NG_L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */
#define NG_L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */
#define NG_L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */
#define NG_L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */
/* 0x0006 - 0x1000 - reserved for future use */
/* L2CAP Connection response command result codes */
#define NG_L2CAP_SUCCESS 0x0000
#define NG_L2CAP_PENDING 0x0001
#define NG_L2CAP_PSM_NOT_SUPPORTED 0x0002
#define NG_L2CAP_SEQUIRY_BLOCK 0x0003
#define NG_L2CAP_NO_RESOURCES 0x0004
#define NG_L2CAP_TIMEOUT 0xeeee
#define NG_L2CAP_UNKNOWN 0xffff
/* 0x0005 - 0xffff - reserved for future use */
/* L2CAP Connection response status codes */
#define NG_L2CAP_NO_INFO 0x0000
#define NG_L2CAP_AUTH_PENDING 0x0001
#define NG_L2CAP_AUTZ_PENDING 0x0002
/* 0x0003 - 0xffff - reserved for future use */
/* L2CAP Configuration response result codes */
#define NG_L2CAP_UNACCEPTABLE_PARAMS 0x0001
#define NG_L2CAP_REJECT 0x0002
#define NG_L2CAP_UNKNOWN_OPTION 0x0003
/* 0x0003 - 0xffff - reserved for future use */
/* L2CAP Configuration options */
#define NG_L2CAP_OPT_CFLAG_BIT 0x0001
#define NG_L2CAP_OPT_CFLAG(flags) ((flags) & NG_L2CAP_OPT_CFLAG_BIT)
#define NG_L2CAP_OPT_HINT_BIT 0x80
#define NG_L2CAP_OPT_HINT(type) ((type) & NG_L2CAP_OPT_HINT_BIT)
#define NG_L2CAP_OPT_HINT_MASK 0x7f
#define NG_L2CAP_OPT_MTU 0x01
#define NG_L2CAP_OPT_MTU_SIZE sizeof(u_int16_t)
#define NG_L2CAP_OPT_FLUSH_TIMO 0x02
#define NG_L2CAP_OPT_FLUSH_TIMO_SIZE sizeof(u_int16_t)
#define NG_L2CAP_OPT_QOS 0x03
#define NG_L2CAP_OPT_QOS_SIZE sizeof(ng_l2cap_flow_t)
/* 0x4 - 0xff - reserved for future use */
/* L2CAP Information request type codes */
#define NG_L2CAP_CONNLESS_MTU 0x0001
/* 0x0002 - 0xffff - reserved for future use */
/* L2CAP Information response codes */
#define NG_L2CAP_NOT_SUPPORTED 0x0001
/* 0x0002 - 0xffff - reserved for future use */
/* L2CAP flow control */
typedef struct {
u_int8_t flags; /* reserved for future use */
u_int8_t service_type; /* service type */
u_int32_t token_rate; /* bytes per second */
u_int32_t token_bucket_size; /* bytes */
u_int32_t peak_bandwidth; /* bytes per second */
u_int32_t latency; /* microseconds */
u_int32_t delay_variation; /* microseconds */
} __attribute__ ((packed)) ng_l2cap_flow_t;
typedef ng_l2cap_flow_t * ng_l2cap_flow_p;
/**************************************************************************
**************************************************************************
** Link level defines, headers and types
**************************************************************************
**************************************************************************/
/* L2CAP header */
typedef struct {
u_int16_t length; /* payload size */
u_int16_t dcid; /* destination channel ID */
} __attribute__ ((packed)) ng_l2cap_hdr_t;
/* L2CAP ConnectionLess Traffic (CLT) (if destination cid == 0x2) */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
} __attribute__ ((packed)) ng_l2cap_clt_hdr_t;
#define NG_L2CAP_CLT_MTU_MAXIMUM \
(NG_L2CAP_MTU_MAXIMUM - sizeof(ng_l2cap_clt_hdr_t))
/* L2CAP command header */
typedef struct {
u_int8_t code; /* command OpCode */
u_int8_t ident; /* identifier to match request and response */
u_int16_t length; /* command parameters length */
} __attribute__ ((packed)) ng_l2cap_cmd_hdr_t;
/* L2CAP Command Reject */
#define NG_L2CAP_CMD_REJ 0x01
typedef struct {
u_int16_t reason; /* reason to reject command */
/* u_int8_t data[]; -- optional data (depends on reason) */
} __attribute__ ((packed)) ng_l2cap_cmd_rej_cp;
/* CommandReject data */
typedef union {
/* NG_L2CAP_REJ_MTU_EXCEEDED */
struct {
u_int16_t mtu; /* actual signaling MTU */
} __attribute__ ((packed)) mtu;
/* NG_L2CAP_REJ_INVALID_CID */
struct {
u_int16_t scid; /* local CID */
u_int16_t dcid; /* remote CID */
} __attribute__ ((packed)) cid;
} ng_l2cap_cmd_rej_data_t;
typedef ng_l2cap_cmd_rej_data_t * ng_l2cap_cmd_rej_data_p;
/* L2CAP Connection Request */
#define NG_L2CAP_CON_REQ 0x02
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor (PSM) */
u_int16_t scid; /* source channel ID */
} __attribute__ ((packed)) ng_l2cap_con_req_cp;
/* L2CAP Connection Response */
#define NG_L2CAP_CON_RSP 0x03
typedef struct {
u_int16_t dcid; /* destination channel ID */
u_int16_t scid; /* source channel ID */
u_int16_t result; /* 0x00 - success */
u_int16_t status; /* more info if result != 0x00 */
} __attribute__ ((packed)) ng_l2cap_con_rsp_cp;
/* L2CAP Configuration Request */
#define NG_L2CAP_CFG_REQ 0x04
typedef struct {
u_int16_t dcid; /* destination channel ID */
u_int16_t flags; /* flags */
/* u_int8_t options[] -- options */
} __attribute__ ((packed)) ng_l2cap_cfg_req_cp;
/* L2CAP Configuration Response */
#define NG_L2CAP_CFG_RSP 0x05
typedef struct {
u_int16_t scid; /* source channel ID */
u_int16_t flags; /* flags */
u_int16_t result; /* 0x00 - success */
/* u_int8_t options[] -- options */
} __attribute__ ((packed)) ng_l2cap_cfg_rsp_cp;
/* L2CAP configuration option */
typedef struct {
u_int8_t type;
u_int8_t length;
/* u_int8_t value[] -- option value (depends on type) */
} __attribute__ ((packed)) ng_l2cap_cfg_opt_t;
typedef ng_l2cap_cfg_opt_t * ng_l2cap_cfg_opt_p;
/* L2CAP configuration option value */
typedef union {
u_int16_t mtu; /* NG_L2CAP_OPT_MTU */
u_int16_t flush_timo; /* NG_L2CAP_OPT_FLUSH_TIMO */
ng_l2cap_flow_t flow; /* NG_L2CAP_OPT_QOS */
} ng_l2cap_cfg_opt_val_t;
typedef ng_l2cap_cfg_opt_val_t * ng_l2cap_cfg_opt_val_p;
/* L2CAP Disconnect Request */
#define NG_L2CAP_DISCON_REQ 0x06
typedef struct {
u_int16_t dcid; /* destination channel ID */
u_int16_t scid; /* source channel ID */
} __attribute__ ((packed)) ng_l2cap_discon_req_cp;
/* L2CAP Disconnect Response */
#define NG_L2CAP_DISCON_RSP 0x07
typedef ng_l2cap_discon_req_cp ng_l2cap_discon_rsp_cp;
/* L2CAP Echo Request */
#define NG_L2CAP_ECHO_REQ 0x08
/* No command parameters, only optional data */
/* L2CAP Echo Response */
#define NG_L2CAP_ECHO_RSP 0x09
#define NG_L2CAP_MAX_ECHO_SIZE \
(NG_L2CAP_MTU_MAXIMUM - sizeof(ng_l2cap_cmd_hdr_t))
/* No command parameters, only optional data */
/* L2CAP Information Request */
#define NG_L2CAP_INFO_REQ 0x0a
typedef struct {
u_int16_t type; /* requested information type */
} __attribute__ ((packed)) ng_l2cap_info_req_cp;
/* L2CAP Information Response */
#define NG_L2CAP_INFO_RSP 0x0b
typedef struct {
u_int16_t type; /* requested information type */
u_int16_t result; /* 0x00 - success */
/* u_int8_t info[] -- info data (depends on type)
*
* NG_L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU
*/
} __attribute__ ((packed)) ng_l2cap_info_rsp_cp;
typedef union {
/* NG_L2CAP_CONNLESS_MTU */
struct {
u_int16_t mtu;
} __attribute__ ((packed)) mtu;
} ng_l2cap_info_rsp_data_t;
typedef ng_l2cap_info_rsp_data_t * ng_l2cap_info_rsp_data_p;
/**************************************************************************
**************************************************************************
** Upper layer protocol interface. L2CA_xxx messages
**************************************************************************
**************************************************************************/
/*
* NOTE! NOTE! NOTE!
*
* Bluetooth specification says that L2CA_xxx request must block until
* response is ready. We are not allowed to block in Netgraph, so we
* need to queue request and save some information that can be used
* later and help match request and response.
*
* The idea is to use "token" field from Netgraph message header. The
* upper layer protocol _MUST_ populate "token". L2CAP will queue request
* (using L2CAP command descriptor) and start processing. Later, when
* response is ready or timeout has occur L2CAP layer will create new
* Netgraph message, set "token" and RESP flag and send the message to
* the upper layer protocol.
*
* L2CA_xxx_Ind messages _WILL_NOT_ populate "token" and _WILL_NOT_
* set RESP flag. There is no reason for this, because they are just
* notifications and do not require acknowlegment.
*
* NOTE: This is _NOT_ what NG_MKRESPONSE and NG_RESPOND_MSG do, however
* it is somewhat similar.
*/
/* L2CA data packet header */
typedef struct {
u_int32_t token; /* token to use in L2CAP_L2CA_WRITE */
u_int16_t length; /* length of the data */
u_int16_t lcid; /* local channel ID */
} __attribute__ ((packed)) ng_l2cap_l2ca_hdr_t;
/* L2CA_Connect */
#define NGM_L2CAP_L2CA_CON 0x80
/* Upper -> L2CAP */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
bdaddr_t bdaddr; /* remote unit address */
} ng_l2cap_l2ca_con_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t result; /* 0x00 - success */
u_int16_t status; /* if result != 0x00 */
} ng_l2cap_l2ca_con_op;
/* L2CA_ConnectInd */
#define NGM_L2CAP_L2CA_CON_IND 0x81
/* L2CAP -> Upper */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int16_t lcid; /* local channel ID */
u_int16_t psm; /* Procotol/Service Multiplexor */
u_int8_t ident; /* indentifier */
u_int8_t unused; /* place holder */
} ng_l2cap_l2ca_con_ind_ip;
/* No output parameters */
/* L2CA_ConnectRsp */
#define NGM_L2CAP_L2CA_CON_RSP 0x82
/* Upper -> L2CAP */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int8_t ident; /* "ident" from L2CAP_ConnectInd event */
u_int8_t unused; /* place holder */
u_int16_t lcid; /* local channel ID */
u_int16_t result; /* 0x00 - success */
u_int16_t status; /* if response != 0x00 */
} ng_l2cap_l2ca_con_rsp_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
} ng_l2cap_l2ca_con_rsp_op;
/* L2CA_Config */
#define NGM_L2CAP_L2CA_CFG 0x83
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t imtu; /* receiving MTU for the local channel */
ng_l2cap_flow_t oflow; /* out flow */
u_int16_t flush_timo; /* flush timeout (msec) */
u_int16_t link_timo; /* link timeout (msec) */
} ng_l2cap_l2ca_cfg_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
u_int16_t imtu; /* sending MTU for the remote channel */
ng_l2cap_flow_t oflow; /* out flow */
u_int16_t flush_timo; /* flush timeout (msec) */
} ng_l2cap_l2ca_cfg_op;
/* L2CA_ConfigRsp */
#define NGM_L2CAP_L2CA_CFG_RSP 0x84
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t omtu; /* sending MTU for the local channel */
ng_l2cap_flow_t iflow; /* in FLOW */
} ng_l2cap_l2ca_cfg_rsp_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - sucsess */
} ng_l2cap_l2ca_cfg_rsp_op;
/* L2CA_ConfigInd */
#define NGM_L2CAP_L2CA_CFG_IND 0x85
/* L2CAP -> Upper */
typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t omtu; /* outgoing MTU for the local channel */
ng_l2cap_flow_t iflow; /* in flow */
u_int16_t flush_timo; /* flush timeout (msec) */
} ng_l2cap_l2ca_cfg_ind_ip;
/* No output parameters */
/* L2CA_QoSViolationInd */
#define NGM_L2CAP_L2CA_QOS_IND 0x86
/* L2CAP -> Upper */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
} ng_l2cap_l2ca_qos_ind_ip;
/* No output parameters */
/* L2CA_Disconnect */
#define NGM_L2CAP_L2CA_DISCON 0x87
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local channel ID */
} ng_l2cap_l2ca_discon_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - sucsess */
} ng_l2cap_l2ca_discon_op;
/* L2CA_DisconnectInd */
#define NGM_L2CAP_L2CA_DISCON_IND 0x88
/* L2CAP -> Upper */
typedef ng_l2cap_l2ca_discon_ip ng_l2cap_l2ca_discon_ind_ip;
/* No output parameters */
/* L2CA_Write response */
#define NGM_L2CAP_L2CA_WRITE 0x89
/* No input parameters */
/* L2CAP -> Upper */
typedef struct {
int result; /* result (0x00 - success) */
u_int16_t length; /* amount of data written */
u_int16_t lcid; /* local channel ID */
} ng_l2cap_l2ca_write_op;
/* L2CA_GroupCreate */
#define NGM_L2CAP_L2CA_GRP_CREATE 0x8a
/* Upper -> L2CAP */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
} ng_l2cap_l2ca_grp_create_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t lcid; /* local group channel ID */
} ng_l2cap_l2ca_grp_create_op;
/* L2CA_GroupClose */
#define NGM_L2CAP_L2CA_GRP_CLOSE 0x8b
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local group channel ID */
} ng_l2cap_l2ca_grp_close_ip;
#if 0
/* L2CAP -> Upper */
* typedef struct {
* u_int16_t result; /* 0x00 - success */
* } ng_l2cap_l2ca_grp_close_op;
#endif
/* L2CA_GroupAddMember */
#define NGM_L2CAP_L2CA_GRP_ADD_MEMBER 0x8c
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local group channel ID */
bdaddr_t bdaddr; /* remote unit address */
} ng_l2cap_l2ca_grp_add_member_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
} ng_l2cap_l2ca_grp_add_member_op;
/* L2CA_GroupRemoveMember */
#define NGM_L2CAP_L2CA_GRP_REM_MEMBER 0x8d
/* Upper -> L2CAP */
typedef ng_l2cap_l2ca_grp_add_member_ip ng_l2cap_l2ca_grp_rem_member_ip;
/* L2CAP -> Upper */
#if 0
* typedef ng_l2cap_l2ca_grp_add_member_op ng_l2cap_l2ca_grp_rem_member_op;
#endif
/* L2CA_GroupMembeship */
#define NGM_L2CAP_L2CA_GRP_MEMBERSHIP 0x8e
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local group channel ID */
} ng_l2cap_l2ca_grp_get_members_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
u_int16_t nmembers; /* number of group members */
/* bdaddr_t members[] -- group memebers */
} ng_l2cap_l2ca_grp_get_members_op;
/* L2CA_Ping */
#define NGM_L2CAP_L2CA_PING 0x8f
/* Upper -> L2CAP */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int16_t echo_size; /* size of echo data in bytes */
/* u_int8_t echo_data[] -- echo data */
} ng_l2cap_l2ca_ping_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
bdaddr_t bdaddr; /* remote unit address */
u_int16_t echo_size; /* size of echo data in bytes */
/* u_int8_t echo_data[] -- echo data */
} ng_l2cap_l2ca_ping_op;
/* L2CA_GetInfo */
#define NGM_L2CAP_L2CA_GET_INFO 0x90
/* Upper -> L2CAP */
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int16_t info_type; /* info type */
} ng_l2cap_l2ca_get_info_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t result; /* 0x00 - success */
u_int16_t info_size; /* size of info data in bytes */
/* u_int8_t info_data[] -- info data */
} ng_l2cap_l2ca_get_info_op;
/* L2CA_EnableCLT/L2CA_DisableCLT */
#define NGM_L2CAP_L2CA_ENABLE_CLT 0x91
/* Upper -> L2CAP */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
u_int16_t enable; /* 0x00 - disable */
} ng_l2cap_l2ca_enable_clt_ip;
#if 0
/* L2CAP -> Upper */
* typedef struct {
* u_int16_t result; /* 0x00 - success */
* } ng_l2cap_l2ca_enable_clt_op;
#endif
/**************************************************************************
**************************************************************************
** L2CAP node messages
**************************************************************************
**************************************************************************/
/* L2CAP connection states */
#define NG_L2CAP_CON_CLOSED 0 /* connection closed */
#define NG_L2CAP_W4_LP_CON_CFM 1 /* waiting... */
#define NG_L2CAP_CON_OPEN 2 /* connection open */
/* L2CAP channel states */
#define NG_L2CAP_CLOSED 0 /* channel closed */
#define NG_L2CAP_W4_L2CAP_CON_RSP 1 /* wait for L2CAP resp. */
#define NG_L2CAP_W4_L2CA_CON_RSP 2 /* wait for upper resp. */
#define NG_L2CAP_CONFIG 3 /* L2CAP configuration */
#define NG_L2CAP_OPEN 4 /* channel open */
#define NG_L2CAP_W4_L2CAP_DISCON_RSP 5 /* wait for L2CAP discon. */
#define NG_L2CAP_W4_L2CA_DISCON_RSP 6 /* wait for upper discon. */
/* Node flags */
#define NG_L2CAP_CLT_SDP_DISABLED (1 << 0) /* disable SDP CLT */
#define NG_L2CAP_CLT_RFCOMM_DISABLED (1 << 1) /* disable RFCOMM CLT */
#define NG_L2CAP_CLT_TCP_DISABLED (1 << 2) /* disable TCP CLT */
/* Debug levels */
#define NG_L2CAP_ALERT_LEVEL 1
#define NG_L2CAP_ERR_LEVEL 2
#define NG_L2CAP_WARN_LEVEL 3
#define NG_L2CAP_INFO_LEVEL 4
/* Get node flags (see flags above) */
#define NGM_L2CAP_NODE_GET_FLAGS 0x400 /* L2CAP -> User */
typedef u_int16_t ng_l2cap_node_flags_ep;
/* Get/Set debug level (see levels above) */
#define NGM_L2CAP_NODE_GET_DEBUG 0x401 /* L2CAP -> User */
#define NGM_L2CAP_NODE_SET_DEBUG 0x402 /* User -> L2CAP */
typedef u_int16_t ng_l2cap_node_debug_ep;
#define NGM_L2CAP_NODE_HOOK_INFO 0x409 /* L2CAP -> Upper */
/* bdaddr_t bdaddr; -- local (source BDADDR) */
#define NGM_L2CAP_NODE_GET_CON_LIST 0x40a /* User -> L2CAP */
typedef struct {
u_int32_t num_connections; /* number of connections */
} ng_l2cap_node_con_list_ep;
/* Connection flags */
#define NG_L2CAP_CON_TX (1 << 0) /* sending data */
#define NG_L2CAP_CON_RX (1 << 1) /* receiving data */
typedef struct {
u_int8_t state; /* connection state */
u_int8_t flags; /* flags */
int16_t pending; /* num. pending packets */
u_int16_t con_handle; /* connection handle */
bdaddr_t remote; /* remote bdaddr */
} ng_l2cap_node_con_ep;
#define NG_L2CAP_MAX_CON_NUM \
((0xffff - sizeof(ng_l2cap_node_con_list_ep))/sizeof(ng_l2cap_node_con_ep))
#define NGM_L2CAP_NODE_GET_CHAN_LIST 0x40b /* User -> L2CAP */
typedef struct {
u_int32_t num_channels; /* number of channels */
} ng_l2cap_node_chan_list_ep;
typedef struct {
u_int32_t state; /* channel state */
u_int16_t scid; /* source (local) channel ID */
u_int16_t dcid; /* destination (remote) channel ID */
u_int16_t imtu; /* incomming MTU */
u_int16_t omtu; /* outgoing MTU */
u_int16_t psm; /* PSM */
bdaddr_t remote; /* remote bdaddr */
} ng_l2cap_node_chan_ep;
#define NG_L2CAP_MAX_CHAN_NUM \
((0xffff - sizeof(ng_l2cap_node_chan_list_ep))/sizeof(ng_l2cap_node_chan_ep))
#endif /* ndef _NETGRAPH_L2CAP_H_ */

View File

@ -0,0 +1,103 @@
/*
* ng_ubt.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_ubt.h,v 1.1 2002/11/09 19:09:02 max Exp $
* $FreeBSD$
*/
#ifndef _NG_UBT_H_
#define _NG_UBT_H_
/* XXX FIXME Does not belong here. Move to usbdevs.h later */
#define USB_VENDOR_MSI 0x0db0 /* MSI www.msi.com.tw */
#define USB_VENDOR_EPOX 0x0a12 /* EPoX www.epox.com */
#define USB_PRODUCT_3COM_3CREB96 0x00a0 /* 3Com Bluetooth USB dongle */
#define USB_PRODUCT_MITSUMI_BT_DONGLE 0x641f /* Mitsumi Bluetooth USB dongle*/
#define USB_PRODUCT_TDK_BT_DONGLE 0x0309 /* TDK Bluetooth USB dongle */
#define USB_PRODUCT_MSI_BT_DONGLE 0x1967 /* MSI Bluetooth USB dongle */
#define USB_PRODUCT_DBW_120M_BT_DONGLE 0x2033 /* D-Link DBW-120M */
#define USB_PRODUCT_BT_DG02_DONGLE 0x0001 /* EPoX BT-DG02 USB dongle */
/* XXX FIXME Does not belong here. Move to usb.h later */
#define UICLASS_WIRELESS_CONTROLLER 0xe0 /* Wireless Controller */
#define UISUBCLASS_RF_CONTROLLER 0x01 /* RF Controller */
#define UIPROTO_BLUETOOTH 0x01 /* Bluetooth programming */
/**************************************************************************
**************************************************************************
** Netgraph node hook name, type name and type cookie and commands
**************************************************************************
**************************************************************************/
#define NG_UBT_NODE_TYPE "ubt"
#define NG_UBT_HOOK "hook"
#define NGM_UBT_COOKIE 1021837971
/* Debug levels */
#define NG_UBT_ALERT_LEVEL 1
#define NG_UBT_ERR_LEVEL 2
#define NG_UBT_WARN_LEVEL 3
#define NG_UBT_INFO_LEVEL 4
/**************************************************************************
**************************************************************************
** UBT node command/event parameters
**************************************************************************
**************************************************************************/
#define NGM_UBT_NODE_SET_DEBUG 1 /* set debug level */
#define NGM_UBT_NODE_GET_DEBUG 2 /* get debug level */
typedef u_int16_t ng_ubt_node_debug_ep;
#define NGM_UBT_NODE_SET_QLEN 3 /* set queue length */
#define NGM_UBT_NODE_GET_QLEN 4 /* get queue length */
typedef struct {
int32_t queue; /* queue index */
#define NGM_UBT_NODE_QUEUE_IN 1 /* incoming queue */
#define NGM_UBT_NODE_QUEUE_CMD 2 /* commands */
#define NGM_UBT_NODE_QUEUE_ACL 3 /* ACL data */
#define NGM_UBT_NODE_QUEUE_SCO 4 /* SCO data */
int32_t qlen; /* queue length */
} ng_ubt_node_qlen_ep;
#define NGM_UBT_NODE_GET_STAT 5 /* get statistic */
typedef struct {
u_int32_t pckts_recv; /* # of packets received */
u_int32_t bytes_recv; /* # of bytes received */
u_int32_t pckts_sent; /* # of packets sent */
u_int32_t bytes_sent; /* # of bytes sent */
u_int32_t oerrors; /* # of output errors */
u_int32_t ierrors; /* # of input errors */
} ng_ubt_node_stat_ep;
#define NGM_UBT_NODE_RESET_STAT 6 /* reset statistic */
#endif /* ndef _NG_UBT_H_ */

View File

@ -0,0 +1,43 @@
$Id: TODO,v 1.8 2002/09/06 21:03:58 max Exp $
$FreeBSD$
FIXME/TODO list
0) Ping itself. Should L2CAP layer loopback data?
1) Locking/SMP
External code now uses ng_send_fn to inject data into Netgraph, so
it should be fine as long as Netgraph is SMP safe. Just need to
verify it.
2) Understand and implement L2CAP QoS
Will fix later. I only have CSR based hardware and it does not
support QoS.
3) Better functions to manage CIDs and command ident's.
Resource manager is not good because it uses MTX_DEF mutexes,
(i.e. could block/sleep)
4) Implement group channels (multicast)
Will fix later
5) Add bytes/packets counters and commands to get/reset them
Will fix later. What to count?
6) Better way to get information about channels
L2CAP can support about 65000 channels. Need define some good way
to get data from kernel to user space. For example if we need to pass
1K of information for every channel, then worst case is that we need
to pass 65Mbytes of data from kernel to user space. Not good.
7) Deal properly with "shutdown"s and hook "disconnect"s
For now we destroy all channels when upstream hook is disconnected.
Is there a better way to handle this?

View File

@ -0,0 +1,365 @@
/*
* ng_l2cap_cmds.c
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_cmds.c,v 1.14 2002/09/04 21:38:38 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include "ng_bluetooth.h"
#include "ng_hci.h"
#include "ng_l2cap.h"
#include "ng_l2cap_var.h"
#include "ng_l2cap_cmds.h"
#include "ng_l2cap_evnt.h"
#include "ng_l2cap_llpi.h"
#include "ng_l2cap_ulpi.h"
#include "ng_l2cap_misc.h"
/******************************************************************************
******************************************************************************
** L2CAP commands processing module
******************************************************************************
******************************************************************************/
/*
* Process L2CAP command queue on connection
*/
void
ng_l2cap_con_wakeup(ng_l2cap_con_p con)
{
ng_l2cap_cmd_p cmd = NULL;
struct mbuf *m = NULL;
int error = 0;
/* Find first non-pending command in the queue */
TAILQ_FOREACH(cmd, &con->cmd_list, next) {
KASSERT((cmd->con == con),
("%s: %s - invalid connection pointer!\n",
__func__, NG_NODE_NAME(con->l2cap->node)));
if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
break;
}
if (cmd == NULL)
return;
/* Detach command packet */
m = cmd->aux;
cmd->aux = NULL;
/* Process command */
switch (cmd->code) {
case NG_L2CAP_CMD_REJ:
case NG_L2CAP_DISCON_RSP:
case NG_L2CAP_ECHO_RSP:
case NG_L2CAP_INFO_RSP:
ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
break;
case NG_L2CAP_CON_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
NG_L2CAP_NO_RESOURCES, 0);
ng_l2cap_free_chan(cmd->ch); /* will free commands */
} else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NG_L2CAP_CON_RSP:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_unlink_cmd(cmd);
if (cmd->ch != NULL) {
ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
(error == 0)? NG_L2CAP_SUCCESS :
NG_L2CAP_NO_RESOURCES);
if (error != 0)
ng_l2cap_free_chan(cmd->ch);
}
ng_l2cap_free_cmd(cmd);
break;
case NG_L2CAP_CFG_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token,
NG_L2CAP_NO_RESOURCES);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NG_L2CAP_CFG_RSP:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_unlink_cmd(cmd);
if (cmd->ch != NULL)
ng_l2cap_l2ca_cfg_rsp_rsp(cmd->ch, cmd->token,
(error == 0)? NG_L2CAP_SUCCESS :
NG_L2CAP_NO_RESOURCES);
ng_l2cap_free_cmd(cmd);
break;
case NG_L2CAP_DISCON_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
(error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES);
if (error != 0)
ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NG_L2CAP_ECHO_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
ng_l2cap_l2ca_ping_rsp(con, cmd->token,
NG_L2CAP_NO_RESOURCES, NULL);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NG_L2CAP_INFO_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
ng_l2cap_l2ca_get_info_rsp(con, cmd->token,
NG_L2CAP_NO_RESOURCES, NULL);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} else
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
case NGM_L2CAP_L2CA_WRITE: {
int length = m->m_pkthdr.len;
if (cmd->ch->dcid == NG_L2CAP_CLT_CID) {
m = ng_l2cap_prepend(m, sizeof(ng_l2cap_clt_hdr_t));
if (m == NULL)
error = ENOBUFS;
else
mtod(m, ng_l2cap_clt_hdr_t *)->psm =
htole16(cmd->ch->psm);
}
if (error == 0)
error = ng_l2cap_lp_send(con, cmd->ch->dcid, m);
ng_l2cap_l2ca_write_rsp(cmd->ch, cmd->token,
(error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES,
length);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} break;
/* XXX FIXME add other commands */
default:
KASSERT(0,
("%s: %s - unknown command code=%d\n",
__func__, NG_NODE_NAME(con->l2cap->node), cmd->code));
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
break;
}
} /* ng_l2cap_con_wakeup */
/*
* We have failed to open ACL connection to the remote unit. Could be negative
* confirmation or timeout. So fail any "delayed" commands, notify upper layer,
* remove all channels and remove connection descriptor.
*/
void
ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
{
ng_l2cap_p l2cap = con->l2cap;
ng_l2cap_cmd_p cmd = NULL;
ng_l2cap_chan_p ch = NULL;
NG_L2CAP_INFO(
"%s: %s - ACL connection failed, result=%d\n",
__func__, NG_NODE_NAME(l2cap->node), result);
/* Clean command queue */
while (!TAILQ_EMPTY(&con->cmd_list)) {
cmd = TAILQ_FIRST(&con->cmd_list);
ng_l2cap_unlink_cmd(cmd);
if(cmd->flags & NG_L2CAP_CMD_PENDING)
ng_l2cap_command_untimeout(cmd);
KASSERT((cmd->con == con),
("%s: %s - invalid connection pointer!\n",
__func__, NG_NODE_NAME(con->l2cap->node)));
switch (cmd->code) {
case NG_L2CAP_CMD_REJ:
case NG_L2CAP_DISCON_RSP:
case NG_L2CAP_ECHO_RSP:
case NG_L2CAP_INFO_RSP:
break;
case NG_L2CAP_CON_REQ:
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, result, 0);
break;
case NG_L2CAP_CON_RSP:
if (cmd->ch != NULL)
ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
result);
break;
case NG_L2CAP_CFG_REQ:
case NG_L2CAP_CFG_RSP:
case NGM_L2CAP_L2CA_WRITE:
ng_l2cap_l2ca_discon_ind(cmd->ch);
break;
case NG_L2CAP_DISCON_REQ:
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
NG_L2CAP_SUCCESS);
break;
case NG_L2CAP_ECHO_REQ:
ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
result, NULL);
break;
case NG_L2CAP_INFO_REQ:
ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
result, NULL);
break;
/* XXX FIXME add other commands */
default:
KASSERT(0,
("%s: %s - unexpected command code=%d\n",
__func__, NG_NODE_NAME(con->l2cap->node),
cmd->code));
break;
}
if (cmd->ch != NULL)
ng_l2cap_free_chan(cmd->ch);
ng_l2cap_free_cmd(cmd);
}
/*
* There still might be channels (in OPEN state?) that
* did not submit any commands, so diconnect them
*/
LIST_FOREACH(ch, &l2cap->chan_list, next)
if (ch->con == con)
ng_l2cap_l2ca_discon_ind(ch);
/* Free connection descriptor */
ng_l2cap_free_con(con);
} /* ng_l2cap_con_fail */
/*
* Process L2CAP command timeout. In general - notify upper layer and destroy
* channel. Do not pay much attension to return code, just do our best.
*/
void
ng_l2cap_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
{
ng_l2cap_cmd_p cmd = (ng_l2cap_cmd_p) arg1;
KASSERT((cmd->flags & NG_L2CAP_CMD_PENDING),
("%s: %s - invalid command flags flags=%#x!\n",
__func__, NG_NODE_NAME(cmd->con->l2cap->node), cmd->flags));
cmd->flags &= ~NG_L2CAP_CMD_PENDING;
ng_l2cap_unlink_cmd(cmd);
switch (cmd->code) {
case NG_L2CAP_CON_REQ:
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT, 0);
ng_l2cap_free_chan(cmd->ch);
break;
case NG_L2CAP_CFG_REQ:
ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
break;
case NG_L2CAP_DISCON_REQ:
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
break;
case NG_L2CAP_ECHO_REQ:
/* Echo request timed out. Let the upper layer know */
ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
NG_L2CAP_TIMEOUT, NULL);
break;
case NG_L2CAP_INFO_REQ:
/* Info request timed out. Let the upper layer know */
ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
NG_L2CAP_TIMEOUT, NULL);
break;
/* XXX FIXME add other commands */
default:
KASSERT(0,
("%s: %s - unexpected command code=%d\n",
__func__, NG_NODE_NAME(cmd->con->l2cap->node),
cmd->code));
break;
}
ng_l2cap_free_cmd(cmd);
} /* ng_l2cap_process_command_timeout */

View File

@ -0,0 +1,403 @@
/*
* ng_l2cap_cmds.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_cmds.h,v 1.9 2002/04/16 00:43:56 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_CMDS_H_
#define _NETGRAPH_L2CAP_CMDS_H_
/******************************************************************************
******************************************************************************
** L2CAP to L2CAP signaling command macros
******************************************************************************
******************************************************************************/
/*
* Note: All L2CAP implementations are required to support minimal signaling
* MTU of 48 bytes. In order to simplify things we will send one command
* per one L2CAP packet. Given evrything above we can assume that one
* signaling packet will fit into single mbuf.
*/
/* L2CAP_CommandRej */
#define _ng_l2cap_cmd_rej(_m, _ident, _reason, _mtu, _scid, _dcid) \
do { \
struct _cmd_rej { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_cmd_rej_cp param; \
ng_l2cap_cmd_rej_data_t data; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
c = mtod((_m), struct _cmd_rej *); \
c->hdr.code = NG_L2CAP_CMD_REJ; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->param); \
\
c->param.reason = htole16((_reason)); \
\
if ((_reason) == NG_L2CAP_REJ_MTU_EXCEEDED) { \
c->data.mtu.mtu = htole16((_mtu)); \
c->hdr.length += sizeof(c->data.mtu); \
} else if ((_reason) == NG_L2CAP_REJ_INVALID_CID) { \
c->data.cid.scid = htole16((_scid)); \
c->data.cid.dcid = htole16((_dcid)); \
c->hdr.length += sizeof(c->data.cid); \
} \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(c->hdr) + \
c->hdr.length; \
\
c->hdr.length = htole16(c->hdr.length); \
} while (0)
/* L2CAP_ConnectReq */
#define _ng_l2cap_con_req(_m, _ident, _psm, _scid) \
do { \
struct _con_req { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_con_req_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _con_req *); \
c->hdr.code = NG_L2CAP_CON_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.psm = htole16((_psm)); \
c->param.scid = htole16((_scid)); \
} while (0)
/* L2CAP_ConnectRsp */
#define _ng_l2cap_con_rsp(_m, _ident, _dcid, _scid, _result, _status) \
do { \
struct _con_rsp { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_con_rsp_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _con_rsp *); \
c->hdr.code = NG_L2CAP_CON_RSP; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.dcid = htole16((_dcid)); \
c->param.scid = htole16((_scid)); \
c->param.result = htole16((_result)); \
c->param.status = htole16((_status)); \
} while (0)
/* L2CAP_ConfigReq */
#define _ng_l2cap_cfg_req(_m, _ident, _dcid, _flags, _data) \
do { \
struct _cfg_req { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_cfg_req_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) { \
NG_FREE_M((_data)); \
break; \
} \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _cfg_req *); \
c->hdr.code = NG_L2CAP_CFG_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->param); \
\
c->param.dcid = htole16((_dcid)); \
c->param.flags = htole16((_flags)); \
if ((_data) != NULL) { \
m_cat((_m), (_data)); \
c->hdr.length += (_data)->m_pkthdr.len; \
(_m)->m_pkthdr.len += (_data)->m_pkthdr.len; \
} \
\
c->hdr.length = htole16(c->hdr.length); \
} while (0)
/* L2CAP_ConfigRsp */
#define _ng_l2cap_cfg_rsp(_m, _ident, _scid, _flags, _result, _data) \
do { \
struct _cfg_rsp { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_cfg_rsp_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) { \
NG_FREE_M((_data)); \
break; \
} \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _cfg_rsp *); \
c->hdr.code = NG_L2CAP_CFG_RSP; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->param); \
\
c->param.scid = htole16((_scid)); \
c->param.flags = htole16((_flags)); \
c->param.result = htole16((_result)); \
if ((_data) != NULL) { \
m_cat((_m), (_data)); \
c->hdr.length += (_data)->m_pkthdr.len; \
(_m)->m_pkthdr.len += (_data)->m_pkthdr.len; \
} \
\
c->hdr.length = htole16(c->hdr.length); \
} while (0)
/* Build configuration options */
#define _ng_l2cap_build_cfg_options(_m, _mtu, _flush_timo, _flow) \
do { \
u_int8_t *p = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = 0; \
p = mtod((_m), u_int8_t *); \
\
if ((_mtu) != NULL) { \
struct _cfg_opt_mtu { \
ng_l2cap_cfg_opt_t hdr; \
u_int16_t val; \
} __attribute__ ((packed)) *o = NULL; \
\
o = (struct _cfg_opt_mtu *) p; \
o->hdr.type = NG_L2CAP_OPT_MTU; \
o->hdr.length = sizeof(o->val); \
o->val = htole16(*(u_int16_t *)(_mtu)); \
\
(_m)->m_pkthdr.len += sizeof(*o); \
p += sizeof(*o); \
} \
\
if ((_flush_timo) != NULL) { \
struct _cfg_opt_flush { \
ng_l2cap_cfg_opt_t hdr; \
u_int16_t val; \
} __attribute__ ((packed)) *o = NULL; \
\
o = (struct _cfg_opt_flush *) p; \
o->hdr.type = NG_L2CAP_OPT_FLUSH_TIMO; \
o->hdr.length = sizeof(o->val); \
o->val = htole16(*(u_int16_t *)(_flush_timo)); \
\
(_m)->m_pkthdr.len += sizeof(*o); \
p += sizeof(*o); \
} \
\
if ((_flow) != NULL) { \
struct _cfg_opt_flow { \
ng_l2cap_cfg_opt_t hdr; \
ng_l2cap_flow_t val; \
} __attribute__ ((packed)) *o = NULL; \
\
o = (struct _cfg_opt_flow *) p; \
o->hdr.type = NG_L2CAP_OPT_QOS; \
o->hdr.length = sizeof(o->val); \
o->val.flags = ((ng_l2cap_flow_p)(_flow))->flags; \
o->val.service_type = ((ng_l2cap_flow_p) \
(_flow))->service_type; \
o->val.token_rate = \
htole32(((ng_l2cap_flow_p)(_flow))->token_rate);\
o->val.token_bucket_size = \
htole32(((ng_l2cap_flow_p) \
(_flow))->token_bucket_size); \
o->val.peak_bandwidth = \
htole32(((ng_l2cap_flow_p) \
(_flow))->peak_bandwidth); \
o->val.latency = htole32(((ng_l2cap_flow_p) \
(_flow))->latency); \
o->val.delay_variation = \
htole32(((ng_l2cap_flow_p) \
(_flow))->delay_variation); \
\
(_m)->m_pkthdr.len += sizeof(*o); \
} \
\
(_m)->m_len = (_m)->m_pkthdr.len; \
} while (0)
/* L2CAP_DisconnectReq */
#define _ng_l2cap_discon_req(_m, _ident, _dcid, _scid) \
do { \
struct _discon_req { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_discon_req_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _discon_req *); \
c->hdr.code = NG_L2CAP_DISCON_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.dcid = htole16((_dcid)); \
c->param.scid = htole16((_scid)); \
} while (0)
/* L2CA_DisconnectRsp */
#define _ng_l2cap_discon_rsp(_m, _ident, _dcid, _scid) \
do { \
struct _discon_rsp { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_discon_rsp_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _discon_rsp *); \
c->hdr.code = NG_L2CAP_DISCON_RSP; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.dcid = htole16((_dcid)); \
c->param.scid = htole16((_scid)); \
} while (0)
/* L2CAP_EchoReq */
#define _ng_l2cap_echo_req(_m, _ident, _data, _size) \
do { \
ng_l2cap_cmd_hdr_t *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), ng_l2cap_cmd_hdr_t *); \
c->code = NG_L2CAP_ECHO_REQ; \
c->ident = (_ident); \
c->length = 0; \
\
if ((_data) != NULL) { \
m_copyback((_m), sizeof(*c), (_size), (_data)); \
c->length += (_size); \
} \
\
c->length = htole16(c->length); \
} while (0)
/* L2CAP_InfoReq */
#define _ng_l2cap_info_req(_m, _ident, _type) \
do { \
struct _info_req { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_info_req_cp param; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
\
c = mtod((_m), struct _info_req *); \
c->hdr.code = NG_L2CAP_INFO_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = htole16(sizeof(c->param)); \
\
c->param.type = htole16((_type)); \
} while (0)
/* L2CAP_InfoRsp */
#define _ng_l2cap_info_rsp(_m, _ident, _type, _result, _mtu) \
do { \
struct _info_rsp { \
ng_l2cap_cmd_hdr_t hdr; \
ng_l2cap_info_rsp_cp param; \
ng_l2cap_info_rsp_data_t data; \
} __attribute__ ((packed)) *c = NULL; \
\
MGETHDR((_m), M_DONTWAIT, MT_DATA); \
if ((_m) == NULL) \
break; \
\
c = mtod((_m), struct _info_rsp *); \
c->hdr.code = NG_L2CAP_INFO_REQ; \
c->hdr.ident = (_ident); \
c->hdr.length = sizeof(c->param); \
\
c->param.type = htole16((_type)); \
c->param.result = htole16((_result)); \
\
if ((_result) == NG_L2CAP_SUCCESS) { \
switch ((_type)) { \
case NG_L2CAP_CONNLESS_MTU: \
c->data.mtu.mtu = htole16((_mtu)); \
c->hdr.length += sizeof((c->data.mtu.mtu)); \
break; \
} \
} \
\
(_m)->m_pkthdr.len = (_m)->m_len = sizeof(c->hdr) + \
c->hdr.length; \
\
c->hdr.length = htole16(c->hdr.length); \
} while (0)
void ng_l2cap_con_wakeup (ng_l2cap_con_p);
void ng_l2cap_con_fail (ng_l2cap_con_p, u_int16_t);
void ng_l2cap_process_command_timeout (node_p, hook_p, void *, int);
#endif /* ndef _NETGRAPH_L2CAP_CMDS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
/*
* ng_l2cap_evnt.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_evnt.h,v 1.2 2002/04/16 00:43:56 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_EVNT_H_
#define _NETGRAPH_L2CAP_EVNT_H_
int ng_l2cap_receive (ng_l2cap_con_p);
#endif /* ndef _NETGRAPH_L2CAP_EVNT_H_ */

View File

@ -0,0 +1,806 @@
/*
* ng_l2cap_llpi.c
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_llpi.c,v 1.16 2002/09/04 21:38:38 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include "ng_bluetooth.h"
#include "ng_hci.h"
#include "ng_l2cap.h"
#include "ng_l2cap_var.h"
#include "ng_l2cap_cmds.h"
#include "ng_l2cap_evnt.h"
#include "ng_l2cap_llpi.h"
#include "ng_l2cap_ulpi.h"
#include "ng_l2cap_misc.h"
/******************************************************************************
******************************************************************************
** Lower Layer Protocol (HCI) Interface module
******************************************************************************
******************************************************************************/
/*
* Send LP_ConnectReq event to the lower layer protocol. Create new connection
* descriptor and initialize it. Create LP_ConnectReq event and send it to the
* lower layer, then adjust connection state and start timer. The function WILL
* FAIL if connection to the remote unit already exists.
*/
int
ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr)
{
struct ng_mesg *msg = NULL;
ng_hci_lp_con_req_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Verify that we DO NOT have connection to the remote unit */
con = ng_l2cap_con_by_addr(l2cap, bdaddr);
if (con != NULL) {
NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectReq event. " \
"Connection already exists, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
return (EEXIST);
}
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid\n",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
return (ENOTCONN);
}
/* Create and intialize new connection descriptor */
con = ng_l2cap_new_con(l2cap, bdaddr);
if (con == NULL)
return (ENOMEM);
/* Create and send LP_ConnectReq event */
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
sizeof(*ep), M_NOWAIT);
if (msg == NULL) {
ng_l2cap_free_con(con);
return (ENOMEM);
}
ep = (ng_hci_lp_con_req_ep *) (msg->data);
bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
ep->link_type = NG_HCI_LINK_ACL;
con->state = NG_L2CAP_W4_LP_CON_CFM;
ng_l2cap_lp_timeout(con);
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, NULL);
if (error != 0)
ng_l2cap_free_con(con); /* will remove timeout */
return (error);
} /* ng_l2cap_lp_con_req */
/*
* Process LP_ConnectCfm event from the lower layer protocol. It could be
* positive or negative. Verify remote unit address then stop the timer and
* process event.
*/
int
ng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_con_cfm_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_ConnectCfm[Neg] message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_con_cfm_ep *) (msg->data);
/* Check if we have requested/accepted this connection */
con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n",
__func__, NG_NODE_NAME(l2cap->node));
error = ENOENT;
goto out;
}
/* Check connection state */
if (con->state != NG_L2CAP_W4_LP_CON_CFM) {
NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectCfm event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
error = EINVAL;
goto out;
}
/*
* Looks like it is our confirmation. It is safe now to cancel
* connection timer and notify upper layer.
*/
ng_l2cap_lp_untimeout(con);
if (ep->status == 0) {
con->state = NG_L2CAP_CON_OPEN;
con->con_handle = ep->con_handle;
ng_l2cap_lp_deliver(con);
} else {
/* Negative confirmation - remove connection descriptor */
con->state = NG_L2CAP_CON_CLOSED;
ng_l2cap_con_fail(con, ep->status);
}
out:
return (error);
} /* ng_l2cap_lp_con_cfm */
/*
* Process LP_ConnectInd event from the lower layer protocol. This is a good
* place to put some extra check on remote unit address and/or class. We could
* even forward this information to control hook (or check against internal
* black list) and thus implement some kind of firewall. But for now be simple
* and create new connection descriptor, start timer and send LP_ConnectRsp
* event (i.e. accept connection).
*/
int
ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_con_ind_ep *ep = NULL;
ng_hci_lp_con_rsp_ep *rp = NULL;
struct ng_mesg *rsp = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_ConnectInd message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_con_ind_ep *) (msg->data);
/* Make sure we have only one connection to the remote unit */
con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
if (con != NULL) {
NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectInd event. " \
"Connection already exists, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
error = EEXIST;
goto out;
}
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
error = ENOTCONN;
goto out;
}
/* Create and intialize new connection descriptor */
con = ng_l2cap_new_con(l2cap, &ep->bdaddr);
if (con == NULL) {
error = ENOMEM;
goto out;
}
/* Create and send LP_ConnectRsp event */
NG_MKMESSAGE(rsp, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
sizeof(*rp), M_NOWAIT);
if (msg == NULL) {
ng_l2cap_free_con(con);
error = ENOMEM;
goto out;
}
rp = (ng_hci_lp_con_rsp_ep *)(rsp->data);
rp->status = 0x00; /* accept connection */
rp->link_type = NG_HCI_LINK_ACL;
bcopy(&ep->bdaddr, &rp->bdaddr, sizeof(rp->bdaddr));
con->state = NG_L2CAP_W4_LP_CON_CFM;
ng_l2cap_lp_timeout(con);
NG_SEND_MSG_HOOK(error, l2cap->node, rsp, l2cap->hci, NULL);
if (error != 0)
ng_l2cap_free_con(con); /* will remove timeout */
out:
return (error);
} /* ng_hci_lp_con_ind */
/*
* Process LP_DisconnectInd event from the lower layer protocol. We have been
* disconnected from the remote unit. So notify the upper layer protocol.
*/
int
ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_discon_ind_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_DisconnectInd message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_discon_ind_ep *) (msg->data);
/* Check if we have this connection */
con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_DisconnectInd event. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
error = ENOENT;
goto out;
}
/* XXX Verify connection state -- do we need to check this? */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_DisconnectInd event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
error = EINVAL;
goto out;
}
/* Notify upper layer and remove connection */
con->state = NG_L2CAP_CON_CLOSED;
ng_l2cap_con_fail(con, ep->reason);
out:
return (error);
} /* ng_l2cap_lp_discon_ind */
/*
* Send LP_QoSSetupReq event to the lower layer protocol
*/
int
ng_l2cap_lp_qos_req(ng_l2cap_p l2cap, u_int16_t con_handle,
ng_l2cap_flow_p flow)
{
struct ng_mesg *msg = NULL;
ng_hci_lp_qos_req_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Verify that we have this connection */
con = ng_l2cap_con_by_handle(l2cap, con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSSetupReq event. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con_handle);
return (ENOENT);
}
/* Verify connection state */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSSetupReq event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
return (EINVAL);
}
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
return (ENOTCONN);
}
/* Create and send LP_QoSSetupReq event */
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_REQ,
sizeof(*ep), M_NOWAIT);
if (msg == NULL)
return (ENOMEM);
ep = (ng_hci_lp_qos_req_ep *) (msg->data);
ep->con_handle = con_handle;
ep->flags = flow->flags;
ep->service_type = flow->service_type;
ep->token_rate = flow->token_rate;
ep->peak_bandwidth = flow->peak_bandwidth;
ep->latency = flow->latency;
ep->delay_variation = flow->delay_variation;
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, NULL);
return (error);
} /* ng_l2cap_lp_con_req */
/*
* Process LP_QoSSetupCfm from the lower layer protocol
*/
int
ng_l2cap_lp_qos_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_qos_cfm_ep *ep = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_QoSSetupCfm[Neg] message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_qos_cfm_ep *) (msg->data);
/* XXX FIXME do something */
out:
return (error);
} /* ng_l2cap_lp_qos_cfm */
/*
* Process LP_QoSViolationInd event from the lower layer protocol. Lower
* layer protocol has detected QoS Violation, so we MUST notify the
* upper layer.
*/
int
ng_l2cap_lp_qos_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
ng_hci_lp_qos_ind_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
int error = 0;
/* Check message */
if (msg->header.arglen != sizeof(*ep)) {
NG_L2CAP_ALERT(
"%s: %s - invalid LP_QoSViolation message size\n",
__func__, NG_NODE_NAME(l2cap->node));
error = EMSGSIZE;
goto out;
}
ep = (ng_hci_lp_qos_ind_ep *) (msg->data);
/* Check if we have this connection */
con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSViolationInd event. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
error = ENOENT;
goto out;
}
/* Verify connection state */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSViolationInd event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state,
con->con_handle);
error = EINVAL;
goto out;
}
/* XXX FIXME Notify upper layer and terminate channels if required */
out:
return (error);
} /* ng_l2cap_qos_ind */
/*
* Prepare L2CAP packet. Prepend packet with L2CAP packet header and then
* segment it according to HCI MTU.
*/
int
ng_l2cap_lp_send(ng_l2cap_con_p con, u_int16_t dcid, struct mbuf *m0)
{
ng_l2cap_p l2cap = con->l2cap;
ng_l2cap_hdr_t *l2cap_hdr = NULL;
ng_hci_acldata_pkt_t *acl_hdr = NULL;
struct mbuf *m_last = NULL, *m = NULL;
int len, flag = NG_HCI_PACKET_START;
KASSERT((con->tx_pkt == NULL),
("%s: %s - another packet pending?!\n", __func__, NG_NODE_NAME(l2cap->node)));
KASSERT((l2cap->pkt_size > 0),
("%s: %s - invalid l2cap->pkt_size?!\n", __func__, NG_NODE_NAME(l2cap->node)));
/* Prepend mbuf with L2CAP header */
m0 = ng_l2cap_prepend(m0, sizeof(*l2cap_hdr));
if (m0 == NULL) {
NG_L2CAP_ALERT(
"%s: %s - ng_l2cap_prepend(%d) failed\n",
__func__, NG_NODE_NAME(l2cap->node),
sizeof(*l2cap_hdr));
goto fail;
}
l2cap_hdr = mtod(m0, ng_l2cap_hdr_t *);
l2cap_hdr->length = htole16(m0->m_pkthdr.len - sizeof(*l2cap_hdr));
l2cap_hdr->dcid = htole16(dcid);
/*
* Segment single L2CAP packet according to the HCI layer MTU. Convert
* each segment into ACL data packet and prepend it with ACL data packet
* header. Link all segments together via m_nextpkt link.
*
* XXX BC (Broadcast flag) will always be 0 (zero).
*/
while (m0 != NULL) {
/* Check length of the packet against HCI MTU */
len = m0->m_pkthdr.len;
if (len > l2cap->pkt_size) {
m = m_split(m0, l2cap->pkt_size, M_DONTWAIT);
if (m == NULL) {
NG_L2CAP_ALERT(
"%s: %s - m_split(%d) failed\n", __func__, NG_NODE_NAME(l2cap->node),
l2cap->pkt_size);
goto fail;
}
len = l2cap->pkt_size;
}
/* Convert packet fragment into ACL data packet */
m0 = ng_l2cap_prepend(m0, sizeof(*acl_hdr));
if (m0 == NULL) {
NG_L2CAP_ALERT(
"%s: %s - ng_l2cap_prepend(%d) failed\n",
__func__, NG_NODE_NAME(l2cap->node),
sizeof(*acl_hdr));
goto fail;
}
acl_hdr = mtod(m0, ng_hci_acldata_pkt_t *);
acl_hdr->type = NG_HCI_ACL_DATA_PKT;
acl_hdr->length = htole16(len);
acl_hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(
con->con_handle, flag, 0));
/* Add fragment to the chain */
m0->m_nextpkt = NULL;
if (con->tx_pkt == NULL)
con->tx_pkt = m_last = m0;
else {
m_last->m_nextpkt = m0;
m_last = m0;
}
NG_L2CAP_INFO(
"%s: %s - attaching ACL packet, con_handle=%d, PB=%#x, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->con_handle,
flag, len);
m0 = m;
m = NULL;
flag = NG_HCI_PACKET_FRAGMENT;
}
return (0);
fail:
NG_FREE_M(m0);
NG_FREE_M(m);
while (con->tx_pkt != NULL) {
m = con->tx_pkt->m_nextpkt;
m_freem(con->tx_pkt);
con->tx_pkt = m;
}
return (ENOBUFS);
} /* ng_l2cap_lp_send */
/*
* Receive ACL data packet from the HCI layer. First strip ACL packet header
* and get connection handle, PB (Packet Boundary) flag and payload length.
* Then find connection descriptor and verify its state. Then process ACL
* packet as follows.
*
* 1) If we got first segment (pb == NG_HCI_PACKET_START) then extract L2CAP
* header and get total length of the L2CAP packet. Then start new L2CAP
* packet.
*
* 2) If we got other (then first :) segment (pb == NG_HCI_PACKET_FRAGMENT)
* then add segment to the packet.
*/
int
ng_l2cap_lp_receive(ng_l2cap_p l2cap, struct mbuf *m)
{
ng_hci_acldata_pkt_t *acl_hdr = NULL;
ng_l2cap_hdr_t *l2cap_hdr = NULL;
ng_l2cap_con_p con = NULL;
u_int16_t con_handle, length, pb;
int error = 0;
/* Check ACL data packet */
if (m->m_pkthdr.len < sizeof(*acl_hdr)) {
NG_L2CAP_ERR(
"%s: %s - invalid ACL data packet. Packet too small, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node), m->m_pkthdr.len);
error = EMSGSIZE;
goto drop;
}
/* Strip ACL data packet header */
NG_L2CAP_M_PULLUP(m, sizeof(*acl_hdr));
if (m == NULL)
return (ENOBUFS);
acl_hdr = mtod(m, ng_hci_acldata_pkt_t *);
m_adj(m, sizeof(*acl_hdr));
/* Get ACL connection handle, PB flag and payload length */
acl_hdr->con_handle = le16toh(acl_hdr->con_handle);
con_handle = NG_HCI_CON_HANDLE(acl_hdr->con_handle);
pb = NG_HCI_PB_FLAG(acl_hdr->con_handle);
length = le16toh(acl_hdr->length);
NG_L2CAP_INFO(
"%s: %s - got ACL data packet, con_handle=%d, PB=%#x, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con_handle, pb, length);
/* Get connection descriptor */
con = ng_l2cap_con_by_handle(l2cap, con_handle);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected ACL data packet. " \
"Connection does not exist, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con_handle);
error = ENOENT;
goto drop;
}
/* Verify connection state */
if (con->state != NG_L2CAP_CON_OPEN) {
NG_L2CAP_ERR(
"%s: %s - unexpected ACL data packet. Invalid connection state=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->state);
error = EHOSTDOWN;
goto drop;
}
/* Process packet */
if (pb == NG_HCI_PACKET_START) {
if (con->rx_pkt != NULL) {
NG_L2CAP_ERR(
"%s: %s - dropping incomplete L2CAP packet, got %d bytes, want %d bytes\n",
__func__, NG_NODE_NAME(l2cap->node),
con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
NG_FREE_M(con->rx_pkt);
con->rx_pkt_len = 0;
}
/* Get L2CAP header */
if (m->m_pkthdr.len < sizeof(*l2cap_hdr)) {
NG_L2CAP_ERR(
"%s: %s - invalid L2CAP packet start fragment. Packet too small, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node),
m->m_pkthdr.len);
error = EMSGSIZE;
goto drop;
}
NG_L2CAP_M_PULLUP(m, sizeof(*l2cap_hdr));
if (m == NULL)
return (ENOBUFS);
l2cap_hdr = mtod(m, ng_l2cap_hdr_t *);
NG_L2CAP_INFO(
"%s: %s - staring new L2CAP packet, con_handle=%d, length=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con_handle,
le16toh(l2cap_hdr->length));
/* Start new L2CAP packet */
con->rx_pkt = m;
con->rx_pkt_len = le16toh(l2cap_hdr->length)+sizeof(*l2cap_hdr);
} else if (pb == NG_HCI_PACKET_FRAGMENT) {
if (con->rx_pkt == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected ACL data packet fragment, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node),
con->con_handle);
goto drop;
}
/* Add fragment to the L2CAP packet */
m_cat(con->rx_pkt, m);
con->rx_pkt->m_pkthdr.len += length;
} else {
NG_L2CAP_ERR(
"%s: %s - invalid ACL data packet. Invalid PB flag=%#x\n",
__func__, NG_NODE_NAME(l2cap->node), pb);
error = EINVAL;
goto drop;
}
con->rx_pkt_len -= length;
if (con->rx_pkt_len < 0) {
NG_L2CAP_ALERT(
"%s: %s - packet length mismatch. Got %d bytes, offset %d bytes\n",
__func__, NG_NODE_NAME(l2cap->node),
con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
NG_FREE_M(con->rx_pkt);
con->rx_pkt_len = 0;
} else if (con->rx_pkt_len == 0) {
/* OK, we have got complete L2CAP packet, so process it */
error = ng_l2cap_receive(con);
con->rx_pkt = NULL;
con->rx_pkt_len = 0;
}
return (error);
drop:
NG_FREE_M(m);
return (error);
} /* ng_l2cap_lp_receive */
/*
* Send queued ACL packets to the HCI layer
*/
void
ng_l2cap_lp_deliver(ng_l2cap_con_p con)
{
ng_l2cap_p l2cap = con->l2cap;
struct mbuf *m = NULL;
int error;
/* Check connection */
if (con->state != NG_L2CAP_CON_OPEN)
return;
if (con->tx_pkt == NULL)
ng_l2cap_con_wakeup(con);
if (con->tx_pkt == NULL)
return;
/* Check if lower layer protocol is still connected */
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid",
__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
goto drop; /* XXX what to do with "pending"? */
}
/* Send ACL data packets */
while (con->pending < con->l2cap->num_pkts && con->tx_pkt != NULL) {
m = con->tx_pkt;
con->tx_pkt = con->tx_pkt->m_nextpkt;
m->m_nextpkt = NULL;
NG_L2CAP_INFO(
"%s: %s - sending ACL packet, con_handle=%d, len=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->con_handle,
m->m_pkthdr.len);
NG_SEND_DATA_ONLY(error, l2cap->hci, m);
if (error != 0) {
NG_L2CAP_ERR(
"%s: %s - could not send ACL data packet, con_handle=%d, error=%d\n",
__func__, NG_NODE_NAME(l2cap->node),
con->con_handle, error);
goto drop; /* XXX what to do with "pending"? */
}
con->pending ++;
}
NG_L2CAP_INFO(
"%s: %s - %d ACL packets have been sent, con_handle=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->pending,
con->con_handle);
return;
drop:
while (con->tx_pkt != NULL) {
m = con->tx_pkt->m_nextpkt;
m_freem(con->tx_pkt);
con->tx_pkt = m;
}
} /* ng_l2cap_lp_deliver */
/*
* Process connection timeout. Remove connection from the list. If there
* are any channels that wait for the connection then notify them. Free
* connection descriptor.
*/
void
ng_l2cap_process_lp_timeout(node_p node, hook_p hook, void *arg1, int arg2)
{
ng_l2cap_con_p con = (ng_l2cap_con_p) arg1;
ng_l2cap_p l2cap = con->l2cap;
NG_L2CAP_ERR(
"%s: %s - ACL connection timeout\n", __func__, NG_NODE_NAME(l2cap->node));
/*
* Notify channels that connection has timed out. This will remove
* connection, channels and pending commands.
*/
con->state = NG_L2CAP_CON_CLOSED;
ng_l2cap_con_fail(con, NG_L2CAP_TIMEOUT);
} /* ng_l2cap_process_lp_timeout */

View File

@ -0,0 +1,48 @@
/*
* ng_l2cap_llpi.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_llpi.h,v 1.6 2002/04/16 00:43:57 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_LLPI_H_
#define _NETGRAPH_L2CAP_LLPI_H_
int ng_l2cap_lp_con_req (ng_l2cap_p, bdaddr_p);
int ng_l2cap_lp_con_cfm (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_con_ind (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_discon_ind (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_qos_req (ng_l2cap_p, u_int16_t, ng_l2cap_flow_p);
int ng_l2cap_lp_qos_cfm (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_qos_ind (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_send (ng_l2cap_con_p, u_int16_t,struct mbuf *);
int ng_l2cap_lp_receive (ng_l2cap_p, struct mbuf *);
void ng_l2cap_lp_deliver (ng_l2cap_con_p);
void ng_l2cap_process_lp_timeout (node_p, hook_p, void *, int);
#endif /* ndef _NETGRAPH_L2CAP_LLPI_H_ */

View File

@ -0,0 +1,736 @@
/*
* ng_l2cap_main.c
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_main.c,v 1.24 2002/09/04 21:38:38 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include "ng_bluetooth.h"
#include "ng_hci.h"
#include "ng_l2cap.h"
#include "ng_l2cap_var.h"
#include "ng_l2cap_cmds.h"
#include "ng_l2cap_evnt.h"
#include "ng_l2cap_llpi.h"
#include "ng_l2cap_ulpi.h"
#include "ng_l2cap_misc.h"
#include "ng_l2cap_prse.h"
/******************************************************************************
******************************************************************************
** This node implements Link Layer Control and Adaptation Protocol (L2CAP)
******************************************************************************
******************************************************************************/
/* MALLOC define */
#ifdef NG_SEPARATE_MALLOC
MALLOC_DEFINE(M_NETGRAPH_L2CAP, "netgraph_l2cap",
"Netgraph Bluetooth L2CAP node");
#else
#define M_NETGRAPH_L2CAP M_NETGRAPH
#endif /* NG_SEPARATE_MALLOC */
/* Netgraph node methods */
static ng_constructor_t ng_l2cap_constructor;
static ng_shutdown_t ng_l2cap_shutdown;
static ng_newhook_t ng_l2cap_newhook;
static ng_connect_t ng_l2cap_connect;
static ng_disconnect_t ng_l2cap_disconnect;
static ng_rcvmsg_t ng_l2cap_lower_rcvmsg;
static ng_rcvmsg_t ng_l2cap_upper_rcvmsg;
static ng_rcvmsg_t ng_l2cap_default_rcvmsg;
static ng_rcvdata_t ng_l2cap_rcvdata;
/* Netgraph node type descriptor */
static struct ng_type typestruct = {
NG_ABI_VERSION,
NG_L2CAP_NODE_TYPE, /* typename */
NULL, /* modevent */
ng_l2cap_constructor, /* constructor */
ng_l2cap_default_rcvmsg,/* control message */
ng_l2cap_shutdown, /* destructor */
ng_l2cap_newhook, /* new hook */
NULL, /* findhook */
ng_l2cap_connect, /* connect hook */
ng_l2cap_rcvdata, /* data */
ng_l2cap_disconnect, /* disconnect hook */
ng_l2cap_cmdlist /* node command list */
};
NETGRAPH_INIT(l2cap, &typestruct);
MODULE_VERSION(ng_l2cap, NG_BLUETOOTH_VERSION);
MODULE_DEPEND(ng_l2cap, ng_bluetooth, NG_BLUETOOTH_VERSION,
NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION);
/*****************************************************************************
*****************************************************************************
** Netgraph methods implementation
*****************************************************************************
*****************************************************************************/
static void ng_l2cap_cleanup (ng_l2cap_p);
static void ng_l2cap_destroy_channels (ng_l2cap_p);
/*
* Create new instance of L2CAP node
*/
static int
ng_l2cap_constructor(node_p node)
{
ng_l2cap_p l2cap = NULL;
/* Create new L2CAP node */
MALLOC(l2cap, ng_l2cap_p, sizeof(*l2cap),
M_NETGRAPH_L2CAP, M_NOWAIT|M_ZERO);
if (l2cap == NULL)
return (ENOMEM);
l2cap->node = node;
l2cap->debug = NG_L2CAP_WARN_LEVEL;
LIST_INIT(&l2cap->con_list);
LIST_INIT(&l2cap->chan_list);
NG_NODE_SET_PRIVATE(node, l2cap);
NG_NODE_FORCE_WRITER(node);
return (0);
} /* ng_l2cap_constructor */
/*
* Shutdown L2CAP node
*/
static int
ng_l2cap_shutdown(node_p node)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node);
/* Clean up L2CAP node. Delete all connection, channels and commands */
l2cap->node = NULL;
ng_l2cap_cleanup(l2cap);
bzero(l2cap, sizeof(*l2cap));
FREE(l2cap, M_NETGRAPH_L2CAP);
return (0);
} /* ng_l2cap_shutdown */
/*
* Give our OK for a hook to be added. HCI layer is connected to the HCI
* (NG_L2CAP_HOOK_HCI) hook. As per specification L2CAP layer MUST provide
* Procol/Service Multiplexing, so the L2CAP node provides separate hooks
* for SDP (NG_L2CAP_HOOK_SDP), RFCOMM (NG_L2CAP_HOOK_RFCOMM) and TCP
* (NG_L2CAP_HOOK_TCP) protcols. Unknown PSM will be forwarded to
* NG_L2CAP_HOOK_ORPHAN hook. Control node/application is connected to
* control (NG_L2CAP_HOOK_CTL) hook.
*/
static int
ng_l2cap_newhook(node_p node, hook_p hook, char const *name)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
hook_p *h = NULL;
if (strcmp(name, NG_L2CAP_HOOK_HCI) == 0)
h = &l2cap->hci;
else if (strcmp(name, NG_L2CAP_HOOK_L2C) == 0)
h = &l2cap->l2c;
else if (strcmp(name, NG_L2CAP_HOOK_CTL) == 0)
h = &l2cap->ctl;
else
return (EINVAL);
if (*h != NULL)
return (EISCONN);
*h = hook;
return (0);
} /* ng_l2cap_newhook */
/*
* Give our final OK to connect hook. Nothing to do here.
*/
static int
ng_l2cap_connect(hook_p hook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
int error = 0;
if (hook == l2cap->hci)
NG_HOOK_SET_RCVMSG(hook, ng_l2cap_lower_rcvmsg);
else
if (hook == l2cap->l2c || hook == l2cap->ctl) {
NG_HOOK_SET_RCVMSG(hook, ng_l2cap_upper_rcvmsg);
/* Send delayed notification to the upper layer */
error = ng_send_fn(l2cap->node, hook, ng_l2cap_send_hook_info,
NULL, 0);
} else
error = EINVAL;
return (error);
} /* ng_l2cap_connect */
/*
* Disconnect the hook. For downstream hook we must notify upper layers.
*
* XXX For upstream hooks this is really ugly :( Hook was disconnected and it
* XXX is now too late to do anything. For now we just clean up our own mess
* XXX and remove all channels that use disconnected upstream hook. If we don't
* XXX do that then L2CAP node can get out of sync with upper layers.
* XXX No notification will be sent to remote peer.
*/
static int
ng_l2cap_disconnect(hook_p hook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
hook_p *h = NULL;
if (hook == l2cap->hci) {
ng_l2cap_cleanup(l2cap);
h = &l2cap->hci;
} else
if (hook == l2cap->l2c) {
ng_l2cap_destroy_channels(l2cap);
h = &l2cap->l2c;
} else
if (hook == l2cap->ctl)
h = &l2cap->ctl;
else
return (EINVAL);
*h = NULL;
/* Shutdown when all hooks are disconnected */
if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))
ng_rmnode_self(NG_HOOK_NODE(hook));
return (0);
} /* ng_l2cap_disconnect */
/*
* Process control message from lower layer
*/
static int
ng_l2cap_lower_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
int error = 0;
switch (msg->header.typecookie) {
case NGM_HCI_COOKIE:
switch (msg->header.cmd) {
/* HCI node is ready */
case NGM_HCI_NODE_UP: {
ng_hci_node_up_ep *ep = NULL;
if (msg->header.arglen != sizeof(*ep))
error = EMSGSIZE;
else {
ep = (ng_hci_node_up_ep *)(msg->data);
NG_L2CAP_INFO(
"%s: %s - HCI node is up, bdaddr: %x:%x:%x:%x:%x:%x, " \
"pkt_size=%d bytes, num_pkts=%d\n", __func__, NG_NODE_NAME(l2cap->node),
ep->bdaddr.b[5], ep->bdaddr.b[4],
ep->bdaddr.b[3], ep->bdaddr.b[2],
ep->bdaddr.b[1], ep->bdaddr.b[0],
ep->pkt_size, ep->num_pkts);
bcopy(&ep->bdaddr, &l2cap->bdaddr,
sizeof(l2cap->bdaddr));
l2cap->pkt_size = ep->pkt_size;
l2cap->num_pkts = ep->num_pkts;
/* Notify upper layers */
ng_l2cap_send_hook_info(l2cap->node,
l2cap->l2c, NULL, 0);
ng_l2cap_send_hook_info(l2cap->node,
l2cap->ctl, NULL, 0);
}
} break;
case NGM_HCI_SYNC_CON_QUEUE: {
ng_hci_sync_con_queue_ep *ep = NULL;
ng_l2cap_con_p con = NULL;
if (msg->header.arglen != sizeof(*ep))
error = EMSGSIZE;
else {
ep = (ng_hci_sync_con_queue_ep *)(msg->data);
con = ng_l2cap_con_by_handle(l2cap,
ep->con_handle);
if (con == NULL)
break;
NG_L2CAP_INFO(
"%s: %s - sync HCI connection queue, con_handle=%d, pending=%d, completed=%d\n",
__func__, NG_NODE_NAME(l2cap->node),
ep->con_handle, con->pending,
ep->completed);
con->pending -= ep->completed;
if (con->pending < 0) {
NG_L2CAP_WARN(
"%s: %s - pending packet counter is out of sync! " \
"con_handle=%d, pending=%d, completed=%d\n", __func__,
NG_NODE_NAME(l2cap->node),
con->con_handle, con->pending,
ep->completed);
con->pending = 0;
}
ng_l2cap_lp_deliver(con);
}
} break;
/* LP_ConnectCfm[Neg] */
case NGM_HCI_LP_CON_CFM:
error = ng_l2cap_lp_con_cfm(l2cap, msg);
break;
/* LP_ConnectInd */
case NGM_HCI_LP_CON_IND:
error = ng_l2cap_lp_con_ind(l2cap, msg);
break;
/* LP_DisconnectInd */
case NGM_HCI_LP_DISCON_IND:
error = ng_l2cap_lp_discon_ind(l2cap, msg);
break;
/* LP_QoSSetupCfm[Neg] */
case NGM_HCI_LP_QOS_CFM:
error = ng_l2cap_lp_qos_cfm(l2cap, msg);
break;
/* LP_OoSViolationInd */
case NGM_HCI_LP_QOS_IND:
error = ng_l2cap_lp_qos_ind(l2cap, msg);
break;
default:
error = EINVAL;
break;
}
break;
default:
return (ng_l2cap_default_rcvmsg(node, item, lasthook));
/* NOT REACHED */
}
NG_FREE_ITEM(item);
return (error);
} /* ng_l2cap_lower_rcvmsg */
/*
* Process control message from upper layer
*/
static int
ng_l2cap_upper_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
int error = 0;
switch (msg->header.typecookie) {
case NGM_L2CAP_COOKIE:
switch (msg->header.cmd) {
/* L2CA_Connect */
case NGM_L2CAP_L2CA_CON:
error = ng_l2cap_l2ca_con_req(l2cap, msg);
break;
/* L2CA_ConnectRsp */
case NGM_L2CAP_L2CA_CON_RSP:
error = ng_l2cap_l2ca_con_rsp_req(l2cap, msg);
break;
/* L2CA_Config */
case NGM_L2CAP_L2CA_CFG:
error = ng_l2cap_l2ca_cfg_req(l2cap, msg);
break;
/* L2CA_ConfigRsp */
case NGM_L2CAP_L2CA_CFG_RSP:
error = ng_l2cap_l2ca_cfg_rsp_req(l2cap, msg);
break;
/* L2CA_Disconnect */
case NGM_L2CAP_L2CA_DISCON:
error = ng_l2cap_l2ca_discon_req(l2cap, msg);
break;
/* L2CA_GroupCreate */
case NGM_L2CAP_L2CA_GRP_CREATE:
error = ng_l2cap_l2ca_grp_create(l2cap, msg);
break;
/* L2CA_GroupClose */
case NGM_L2CAP_L2CA_GRP_CLOSE:
error = ng_l2cap_l2ca_grp_close(l2cap, msg);
break;
/* L2CA_GroupAddMember */
case NGM_L2CAP_L2CA_GRP_ADD_MEMBER:
error = ng_l2cap_l2ca_grp_add_member_req(l2cap, msg);
break;
/* L2CA_GroupDeleteMember */
case NGM_L2CAP_L2CA_GRP_REM_MEMBER:
error = ng_l2cap_l2ca_grp_rem_member(l2cap, msg);
break;
/* L2CA_GroupMembership */
case NGM_L2CAP_L2CA_GRP_MEMBERSHIP:
error = ng_l2cap_l2ca_grp_get_members(l2cap, msg);
break;
/* L2CA_Ping */
case NGM_L2CAP_L2CA_PING:
error = ng_l2cap_l2ca_ping_req(l2cap, msg);
break;
/* L2CA_GetInfo */
case NGM_L2CAP_L2CA_GET_INFO:
error = ng_l2cap_l2ca_get_info_req(l2cap, msg);
break;
/* L2CA_EnableCLT */
case NGM_L2CAP_L2CA_ENABLE_CLT:
error = ng_l2cap_l2ca_enable_clt(l2cap, msg);
break;
default:
return (ng_l2cap_default_rcvmsg(node, item, lasthook));
/* NOT REACHED */
}
break;
default:
return (ng_l2cap_default_rcvmsg(node, item, lasthook));
/* NOT REACHED */
}
NG_FREE_ITEM(item);
return (error);
} /* ng_l2cap_upper_rcvmsg */
/*
* Default control message processing routine
*/
static int
ng_l2cap_default_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
struct ng_mesg *msg = NULL, *rsp = NULL;
int error = 0;
/* Detach and process message */
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_GENERIC_COOKIE:
switch (msg->header.cmd) {
case NGM_TEXT_STATUS:
NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT);
if (rsp == NULL)
error = ENOMEM;
else
snprintf(rsp->data, NG_TEXTRESPONSE,
"bdaddr %x:%x:%x:%x:%x:%x, " \
"pkt_size %d\n" \
"Hooks %s %s %s\n" \
"Flags %#x\n",
l2cap->bdaddr.b[5], l2cap->bdaddr.b[4],
l2cap->bdaddr.b[3], l2cap->bdaddr.b[2],
l2cap->bdaddr.b[1], l2cap->bdaddr.b[0],
l2cap->pkt_size,
(l2cap->hci != NULL)?
NG_L2CAP_HOOK_HCI : "",
(l2cap->l2c != NULL)?
NG_L2CAP_HOOK_L2C : "",
(l2cap->ctl != NULL)?
NG_L2CAP_HOOK_CTL : "",
l2cap->flags);
break;
default:
error = EINVAL;
break;
}
break;
/* Messages from the upper layer or directed to the local node */
case NGM_L2CAP_COOKIE:
switch (msg->header.cmd) {
/* Get node flags */
case NGM_L2CAP_NODE_GET_FLAGS:
NG_MKRESPONSE(rsp, msg, sizeof(ng_l2cap_node_flags_ep),
M_NOWAIT);
if (rsp == NULL)
error = ENOMEM;
else
*((ng_l2cap_node_flags_ep *)(rsp->data)) =
l2cap->flags;
break;
/* Get node debug */
case NGM_L2CAP_NODE_GET_DEBUG:
NG_MKRESPONSE(rsp, msg, sizeof(ng_l2cap_node_debug_ep),
M_NOWAIT);
if (rsp == NULL)
error = ENOMEM;
else
*((ng_l2cap_node_debug_ep *)(rsp->data)) =
l2cap->debug;
break;
/* Set node debug */
case NGM_L2CAP_NODE_SET_DEBUG:
if (msg->header.arglen !=
sizeof(ng_l2cap_node_debug_ep))
error = EMSGSIZE;
else
l2cap->debug =
*((ng_l2cap_node_debug_ep *)(msg->data));
break;
/* Get connection list */
case NGM_L2CAP_NODE_GET_CON_LIST: {
ng_l2cap_con_p con = NULL;
ng_l2cap_node_con_list_ep *e1 = NULL;
ng_l2cap_node_con_ep *e2 = NULL;
int n = 0;
/* Count number of connections */
LIST_FOREACH(con, &l2cap->con_list, next)
n++;
if (n > NG_L2CAP_MAX_CON_NUM)
n = NG_L2CAP_MAX_CON_NUM;
/* Prepare response */
NG_MKRESPONSE(rsp, msg,
sizeof(*e1) + n * sizeof(*e2), M_NOWAIT);
if (rsp == NULL) {
error = ENOMEM;
break;
}
e1 = (ng_l2cap_node_con_list_ep *)(rsp->data);
e2 = (ng_l2cap_node_con_ep *)(e1 + 1);
e1->num_connections = n;
LIST_FOREACH(con, &l2cap->con_list, next) {
e2->state = con->state;
if (con->tx_pkt != NULL)
e2->flags |= NG_L2CAP_CON_TX;
if (con->rx_pkt != NULL)
e2->flags |= NG_L2CAP_CON_RX;
e2->pending = con->pending;
e2->con_handle = con->con_handle;
bcopy(&con->remote, &e2->remote,
sizeof(e2->remote));
e2 ++;
if (--n <= 0)
break;
}
} break;
/* Get channel list */
case NGM_L2CAP_NODE_GET_CHAN_LIST: {
ng_l2cap_chan_p ch = NULL;
ng_l2cap_node_chan_list_ep *e1 = NULL;
ng_l2cap_node_chan_ep *e2 = NULL;
int n = 0;
/* Count number of channels */
LIST_FOREACH(ch, &l2cap->chan_list, next)
n ++;
if (n > NG_L2CAP_MAX_CHAN_NUM)
n = NG_L2CAP_MAX_CHAN_NUM;
/* Prepare response */
NG_MKRESPONSE(rsp, msg,
sizeof(ng_l2cap_node_chan_list_ep) +
n * sizeof(ng_l2cap_node_chan_ep), M_NOWAIT);
if (rsp == NULL) {
error = ENOMEM;
break;
}
e1 = (ng_l2cap_node_chan_list_ep *)(rsp->data);
e2 = (ng_l2cap_node_chan_ep *)(e1 + 1);
e1->num_channels = n;
LIST_FOREACH(ch, &l2cap->chan_list, next) {
e2->state = ch->state;
e2->scid = ch->scid;
e2->dcid = ch->dcid;
e2->imtu = ch->imtu;
e2->omtu = ch->omtu;
e2->psm = ch->psm;
bcopy(&ch->con->remote, &e2->remote,
sizeof(e2->remote));
e2 ++;
if (--n <= 0)
break;
}
} break;
default:
error = EINVAL;
break;
}
break;
default:
error = EINVAL;
break;
}
NG_RESPOND_MSG(error, node, item, rsp);
NG_FREE_MSG(msg);
return (error);
} /* ng_l2cap_rcvmsg */
/*
* Process data packet from one of our hooks.
*
* From the HCI hook we expect to receive ACL data packets. ACL data packets
* gets re-assembled into one L2CAP packet (according to length) and then gets
* processed.
*
* NOTE: We expect to receive L2CAP packet header in the first fragment.
* Otherwise we WILL NOT be able to get length of the L2CAP packet.
*
* Signaling L2CAP packets (destination channel ID == 0x1) are processed within
* the node. Connectionless data packets (destination channel ID == 0x2) will
* be forwarded to appropriate upstream hook unless it is not connected or
* connectionless traffic for the specified PSM was disabled.
*
* From the upstream hooks we expect to receive data packets. These data
* packets will be converted into L2CAP data packets. The length of each
* L2CAP packet must not exceed channel's omtu (our peer's imtu). Then
* these L2CAP packets will be converted to ACL data packets (according to
* HCI layer MTU) and sent to lower layer.
*
* No data is expected from the control hook.
*/
static int
ng_l2cap_rcvdata(hook_p hook, item_p item)
{
ng_l2cap_p l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
struct mbuf *m = NULL;
int error = 0;
/* Detach mbuf, discard item and process data */
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
if (hook == l2cap->hci)
error = ng_l2cap_lp_receive(l2cap, m);
else if (hook == l2cap->l2c)
error = ng_l2cap_l2ca_write_req(l2cap, m);
else {
NG_FREE_M(m);
error = EINVAL;
}
return (error);
} /* ng_l2cap_rcvdata */
/*
* Clean all connections, channels and commands for the L2CAP node
*/
static void
ng_l2cap_cleanup(ng_l2cap_p l2cap)
{
ng_l2cap_con_p con = NULL;
/* Clean up connection and channels */
while (!LIST_EMPTY(&l2cap->con_list)) {
con = LIST_FIRST(&l2cap->con_list);
if (con->state == NG_L2CAP_W4_LP_CON_CFM)
ng_l2cap_lp_untimeout(con);
con->state = NG_L2CAP_CON_CLOSED;
ng_l2cap_con_fail(con, 0x16);
/* Connection terminated by local host */
}
} /* ng_l2cap_cleanup */
/*
* Destroy all channels that use specified upstream hook
*/
static void
ng_l2cap_destroy_channels(ng_l2cap_p l2cap)
{
while (!LIST_EMPTY(&l2cap->chan_list))
ng_l2cap_free_chan(LIST_FIRST(&l2cap->chan_list));
} /* ng_l2cap_destroy_channels_by_hook */

View File

@ -0,0 +1,517 @@
/*
* ng_l2cap_misc.c
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_misc.c,v 1.16 2002/09/04 21:38:38 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include "ng_bluetooth.h"
#include "ng_hci.h"
#include "ng_l2cap.h"
#include "ng_l2cap_var.h"
#include "ng_l2cap_cmds.h"
#include "ng_l2cap_evnt.h"
#include "ng_l2cap_llpi.h"
#include "ng_l2cap_ulpi.h"
#include "ng_l2cap_misc.h"
static u_int16_t ng_l2cap_get_cid (ng_l2cap_p);
static void ng_l2cap_queue_lp_timeout (void *);
static void ng_l2cap_queue_command_timeout (void *);
/******************************************************************************
******************************************************************************
** Utility routines
******************************************************************************
******************************************************************************/
/*
* Send hook information to the upper layer
*/
void
ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2)
{
ng_l2cap_p l2cap = NULL;
struct ng_mesg *msg = NULL;
int error = 0;
if (node == NULL || NG_NODE_NOT_VALID(node) ||
hook == NULL || NG_HOOK_NOT_VALID(hook))
return;
l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) ||
bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0)
return;
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO,
sizeof(bdaddr_t), M_NOWAIT);
if (msg != NULL) {
bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t));
NG_SEND_MSG_HOOK(error, node, msg, hook, NULL);
} else
error = ENOMEM;
if (error != 0)
NG_L2CAP_INFO(
"%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n",
__func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook),
error);
} /* ng_l2cap_send_hook_info */
/*
* Create new connection descriptor for the "remote" unit. Will create new
* connection descriptor and signal channel. Will link both connection and
* channel to the l2cap node.
*/
ng_l2cap_con_p
ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr)
{
ng_l2cap_con_p con = NULL;
/* Create new connection descriptor */
MALLOC(con, ng_l2cap_con_p, sizeof(*con), M_NETGRAPH_L2CAP,
M_NOWAIT|M_ZERO);
if (con == NULL)
return (NULL);
con->l2cap = l2cap;
con->state = NG_L2CAP_CON_CLOSED;
bcopy(bdaddr, &con->remote, sizeof(con->remote));
callout_handle_init(&con->con_timo);
con->ident = NG_L2CAP_FIRST_IDENT - 1;
TAILQ_INIT(&con->cmd_list);
/* Link connection */
LIST_INSERT_HEAD(&l2cap->con_list, con, next);
return (con);
} /* ng_l2cap_new_con */
/*
* Free connection descriptor. Will unlink connection and free everything.
*/
void
ng_l2cap_free_con(ng_l2cap_con_p con)
{
ng_l2cap_chan_p f = NULL, n = NULL;
if (con->state == NG_L2CAP_W4_LP_CON_CFM)
ng_l2cap_lp_untimeout(con);
if (con->tx_pkt != NULL) {
while (con->tx_pkt != NULL) {
struct mbuf *m = con->tx_pkt->m_nextpkt;
m_freem(con->tx_pkt);
con->tx_pkt = m;
}
}
NG_FREE_M(con->rx_pkt);
for (f = LIST_FIRST(&con->l2cap->chan_list); f != NULL; ) {
n = LIST_NEXT(f, next);
if (f->con == con)
ng_l2cap_free_chan(f);
f = n;
}
while (!TAILQ_EMPTY(&con->cmd_list)) {
ng_l2cap_cmd_p cmd = TAILQ_FIRST(&con->cmd_list);
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
}
LIST_REMOVE(con, next);
bzero(con, sizeof(*con));
FREE(con, M_NETGRAPH_L2CAP);
} /* ng_l2cap_free_con */
/*
* Get connection by "remote" address
*/
ng_l2cap_con_p
ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr)
{
ng_l2cap_con_p con = NULL;
LIST_FOREACH(con, &l2cap->con_list, next)
if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0)
break;
return (con);
} /* ng_l2cap_con_by_addr */
/*
* Get connection by "handle"
*/
ng_l2cap_con_p
ng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle)
{
ng_l2cap_con_p con = NULL;
LIST_FOREACH(con, &l2cap->con_list, next)
if (con->con_handle == con_handle)
break;
return (con);
} /* ng_l2cap_con_by_handle */
/*
* Allocate new L2CAP channel descriptor on "con" conection with "psm".
* Will link the channel to the l2cap node
*/
ng_l2cap_chan_p
ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm)
{
ng_l2cap_chan_p ch = NULL;
MALLOC(ch, ng_l2cap_chan_p, sizeof(*ch), M_NETGRAPH_L2CAP,
M_NOWAIT|M_ZERO);
if (ch == NULL)
return (NULL);
ch->scid = ng_l2cap_get_cid(l2cap);
if (ch->scid != NG_L2CAP_NULL_CID) {
/* Initialize channel */
ch->psm = psm;
ch->con = con;
ch->state = NG_L2CAP_CLOSED;
/* Set MTU and flow control settings to defaults */
ch->imtu = NG_L2CAP_MTU_DEFAULT;
bcopy(ng_l2cap_default_flow(), &ch->iflow, sizeof(ch->iflow));
ch->omtu = NG_L2CAP_MTU_DEFAULT;
bcopy(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow));
ch->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT;
ch->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT;
LIST_INSERT_HEAD(&l2cap->chan_list, ch, next);
} else {
bzero(ch, sizeof(*ch));
FREE(ch, M_NETGRAPH_L2CAP);
ch = NULL;
}
return (ch);
} /* ng_l2cap_new_chan */
/*
* Get channel by source (local) channel ID
*/
ng_l2cap_chan_p
ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid)
{
ng_l2cap_chan_p ch = NULL;
LIST_FOREACH(ch, &l2cap->chan_list, next)
if (ch->scid == scid)
break;
return (ch);
} /* ng_l2cap_chan_by_scid */
/*
* Free channel descriptor.
*/
void
ng_l2cap_free_chan(ng_l2cap_chan_p ch)
{
ng_l2cap_cmd_p f = NULL, n = NULL;
f = TAILQ_FIRST(&ch->con->cmd_list);
while (f != NULL) {
n = TAILQ_NEXT(f, next);
if (f->ch == ch) {
ng_l2cap_unlink_cmd(f);
ng_l2cap_free_cmd(f);
}
f = n;
}
LIST_REMOVE(ch, next);
bzero(ch, sizeof(*ch));
FREE(ch, M_NETGRAPH_L2CAP);
} /* ng_l2cap_free_chan */
/*
* Create new L2CAP command descriptor. WILL NOT add command to the queue.
*/
ng_l2cap_cmd_p
ng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident,
u_int8_t code, u_int32_t token)
{
ng_l2cap_cmd_p cmd = NULL;
KASSERT((ch == NULL || ch->con == con),
("%s: %s - invalid channel pointer!\n",
__func__, NG_NODE_NAME(con->l2cap->node)));
MALLOC(cmd, ng_l2cap_cmd_p, sizeof(*cmd), M_NETGRAPH_L2CAP,
M_NOWAIT|M_ZERO);
if (cmd == NULL)
return (NULL);
cmd->con = con;
cmd->ch = ch;
cmd->ident = ident;
cmd->code = code;
cmd->token = token;
callout_handle_init(&cmd->timo);
return (cmd);
} /* ng_l2cap_new_cmd */
/*
* Get L2CAP command descriptor by ident
*/
ng_l2cap_cmd_p
ng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident)
{
ng_l2cap_cmd_p cmd = NULL;
TAILQ_FOREACH(cmd, &con->cmd_list, next)
if (cmd->ident == ident)
break;
return (cmd);
} /* ng_l2cap_cmd_by_ident */
/*
* Set LP timeout
*/
void
ng_l2cap_lp_timeout(ng_l2cap_con_p con)
{
NG_NODE_REF(con->l2cap->node);
con->con_timo = timeout(ng_l2cap_queue_lp_timeout, con,
bluetooth_hci_connect_timeout());
} /* ng_l2cap_lp_timeout */
/*
* Unset LP timeout
*/
void
ng_l2cap_lp_untimeout(ng_l2cap_con_p con)
{
untimeout(ng_l2cap_queue_lp_timeout, con, con->con_timo);
NG_NODE_UNREF(con->l2cap->node);
} /* ng_l2cap_lp_untimeout */
/*
* OK, timeout has happend so queue LP timeout processing function
*/
static void
ng_l2cap_queue_lp_timeout(void *context)
{
ng_l2cap_con_p con = (ng_l2cap_con_p) context;
node_p node = con->l2cap->node;
/*
* We need to save node pointer here, because ng_send_fn()
* can execute ng_l2cap_process_lp_timeout() without putting
* item into node's queue (if node can be locked). Once
* ng_l2cap_process_lp_timeout() executed the con pointer
* is no longer valid.
*/
if (NG_NODE_IS_VALID(node))
ng_send_fn(node, NULL, &ng_l2cap_process_lp_timeout, con, 0);
NG_NODE_UNREF(node);
} /* ng_l2cap_queue_lp_timeout */
/*
* Set L2CAP command timeout
*/
void
ng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo)
{
NG_NODE_REF(cmd->con->l2cap->node);
cmd->flags |= NG_L2CAP_CMD_PENDING;
cmd->timo = timeout(ng_l2cap_queue_command_timeout, cmd, timo);
} /* ng_l2cap_command_timeout */
/*
* Unset L2CAP command timeout
*/
void
ng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd)
{
cmd->flags &= ~NG_L2CAP_CMD_PENDING;
untimeout(ng_l2cap_queue_command_timeout, cmd, cmd->timo);
NG_NODE_UNREF(cmd->con->l2cap->node);
} /* ng_l2cap_command_untimeout */
/*
* OK, timeout has happend so queue L2CAP command timeout processing function
*/
static void
ng_l2cap_queue_command_timeout(void *context)
{
ng_l2cap_cmd_p cmd = (ng_l2cap_cmd_p) context;
node_p node = cmd->con->l2cap->node;
/*
* We need to save node pointer here, because ng_send_fn()
* can execute ng_l2cap_process_command_timeout() without
* putting item into node's queue (if node can be locked).
* Once ng_l2cap_process_command_timeout() executed the
* cmd pointer is no longer valid.
*/
if (NG_NODE_IS_VALID(node))
ng_send_fn(node,NULL,&ng_l2cap_process_command_timeout,cmd,0);
NG_NODE_UNREF(node);
} /* ng_l2cap_queue_command_timeout */
/*
* Prepend "m"buf with "size" bytes
*/
struct mbuf *
ng_l2cap_prepend(struct mbuf *m, int size)
{
M_PREPEND(m, size, M_DONTWAIT);
if (m == NULL || (m->m_len < size && (m = m_pullup(m, size)) == NULL))
return (NULL);
return (m);
} /* ng_l2cap_prepend */
/*
* Default flow settings
*/
ng_l2cap_flow_p
ng_l2cap_default_flow(void)
{
static ng_l2cap_flow_t default_flow = {
/* flags */ 0x0,
/* service_type */ NG_HCI_SERVICE_TYPE_BEST_EFFORT,
/* token_rate */ 0xffffffff, /* maximum */
/* token_bucket_size */ 0xffffffff, /* maximum */
/* peak_bandwidth */ 0x00000000, /* maximum */
/* latency */ 0xffffffff, /* don't care */
/* delay_variation */ 0xffffffff /* don't care */
};
return (&default_flow);
} /* ng_l2cap_default_flow */
/*
* Get next available channel ID
* XXX FIXME this is *UGLY* but will do for now
*/
static u_int16_t
ng_l2cap_get_cid(ng_l2cap_p l2cap)
{
u_int16_t cid = l2cap->cid + 1;
if (cid < NG_L2CAP_FIRST_CID)
cid = NG_L2CAP_FIRST_CID;
while (cid != l2cap->cid) {
if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) {
l2cap->cid = cid;
return (cid);
}
cid ++;
if (cid < NG_L2CAP_FIRST_CID)
cid = NG_L2CAP_FIRST_CID;
}
return (NG_L2CAP_NULL_CID);
} /* ng_l2cap_get_cid */
/*
* Get next available command ident
* XXX FIXME this is *UGLY* but will do for now
*/
u_int8_t
ng_l2cap_get_ident(ng_l2cap_con_p con)
{
u_int8_t ident = con->ident + 1;
if (ident < NG_L2CAP_FIRST_IDENT)
ident = NG_L2CAP_FIRST_IDENT;
while (ident != con->ident) {
if (ng_l2cap_cmd_by_ident(con, ident) == NULL) {
con->ident = ident;
return (ident);
}
ident ++;
if (ident < NG_L2CAP_FIRST_IDENT)
ident = NG_L2CAP_FIRST_IDENT;
}
return (NG_L2CAP_NULL_IDENT);
} /* ng_l2cap_get_ident */

View File

@ -0,0 +1,100 @@
/*
* ng_l2cap_misc.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_misc.h,v 1.6 2002/04/16 00:43:57 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_MISC_H_
#define _NETGRAPH_L2CAP_MISC_H_ 1
void ng_l2cap_send_hook_info (node_p, hook_p, void *, int);
/*
* ACL Connections
*/
ng_l2cap_con_p ng_l2cap_new_con (ng_l2cap_p, bdaddr_p);
ng_l2cap_con_p ng_l2cap_con_by_addr (ng_l2cap_p, bdaddr_p);
ng_l2cap_con_p ng_l2cap_con_by_handle (ng_l2cap_p, u_int16_t);
void ng_l2cap_free_con (ng_l2cap_con_p);
/*
* L2CAP channels
*/
ng_l2cap_chan_p ng_l2cap_new_chan (ng_l2cap_p, ng_l2cap_con_p, u_int16_t);
ng_l2cap_chan_p ng_l2cap_chan_by_scid (ng_l2cap_p, u_int16_t);
void ng_l2cap_free_chan (ng_l2cap_chan_p);
/*
* L2CAP command descriptors
*/
#define ng_l2cap_link_cmd(con, cmd) \
do { \
TAILQ_INSERT_TAIL(&(con)->cmd_list, (cmd), next); \
} while (0)
#define ng_l2cap_unlink_cmd(cmd) \
do { \
TAILQ_REMOVE(&((cmd)->con->cmd_list), (cmd), next); \
} while (0)
#define ng_l2cap_free_cmd(cmd) \
do { \
if ((cmd)->flags & NG_L2CAP_CMD_PENDING) \
ng_l2cap_command_untimeout((cmd)); \
\
NG_FREE_M((cmd)->aux); \
bzero((cmd), sizeof(*(cmd))); \
FREE((cmd), M_NETGRAPH_L2CAP); \
} while (0)
ng_l2cap_cmd_p ng_l2cap_new_cmd (ng_l2cap_con_p, ng_l2cap_chan_p,
u_int8_t, u_int8_t, u_int32_t);
ng_l2cap_cmd_p ng_l2cap_cmd_by_ident (ng_l2cap_con_p, u_int8_t);
u_int8_t ng_l2cap_get_ident (ng_l2cap_con_p);
/*
* Timeout
*/
void ng_l2cap_lp_timeout (ng_l2cap_con_p);
void ng_l2cap_lp_untimeout (ng_l2cap_con_p);
void ng_l2cap_command_timeout (ng_l2cap_cmd_p, int);
void ng_l2cap_command_untimeout (ng_l2cap_cmd_p);
/*
* Other stuff
*/
struct mbuf * ng_l2cap_prepend (struct mbuf *, int);
ng_l2cap_flow_p ng_l2cap_default_flow (void);
#endif /* ndef _NETGRAPH_L2CAP_MISC_H_ */

View File

@ -0,0 +1,71 @@
/*
* ng_l2cap_prse.h
*
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_prse.h,v 1.2 2002/09/04 21:38:38 max Exp $
* $FreeBSD$
*/
/***************************************************************************
***************************************************************************
** ng_parse definitions for the L2CAP node
***************************************************************************
***************************************************************************/
#ifndef _NETGRAPH_L2CAP_PRSE_H_
#define _NETGRAPH_L2CAP_PRSE_H_ 1
/*
* L2CAP node command list
*/
static const struct ng_cmdlist ng_l2cap_cmdlist[] = {
{
NGM_L2CAP_COOKIE,
NGM_L2CAP_NODE_GET_FLAGS,
"get_flags",
NULL,
&ng_parse_uint16_type
},
{
NGM_L2CAP_COOKIE,
NGM_L2CAP_NODE_GET_DEBUG,
"get_debug",
NULL,
&ng_parse_uint16_type
},
{
NGM_L2CAP_COOKIE,
NGM_L2CAP_NODE_SET_DEBUG,
"set_debug",
&ng_parse_uint16_type,
NULL
},
{ 0, }
};
#endif /* ndef _NETGRAPH_L2CAP_PRSE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
/*
* ng_l2cap_ulpi.h
*
* Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_ulpi.h,v 1.5 2002/07/04 21:48:53 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_ULPI_H_
#define _NETGRAPH_L2CAP_ULPI_H_
int ng_l2cap_l2ca_con_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_con_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t, u_int16_t);
int ng_l2cap_l2ca_con_rsp_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_con_rsp_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_con_ind (ng_l2cap_chan_p);
int ng_l2cap_l2ca_cfg_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_cfg_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_cfg_rsp_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_cfg_rsp_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_cfg_ind (ng_l2cap_chan_p);
int ng_l2cap_l2ca_write_req (ng_l2cap_p, struct mbuf *);
int ng_l2cap_l2ca_write_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t, u_int16_t);
int ng_l2cap_l2ca_receive (ng_l2cap_con_p);
int ng_l2cap_l2ca_clt_receive (ng_l2cap_con_p);
int ng_l2cap_l2ca_qos_ind (ng_l2cap_chan_p);
int ng_l2cap_l2ca_discon_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_discon_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_discon_ind (ng_l2cap_chan_p);
int ng_l2cap_l2ca_grp_create (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_grp_close (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_grp_add_member_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_grp_add_member_rsp (ng_l2cap_chan_p, u_int32_t, u_int16_t);
int ng_l2cap_l2ca_grp_rem_member (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_grp_get_members (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_ping_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_ping_rsp (ng_l2cap_con_p, u_int32_t, u_int16_t,
struct mbuf *);
int ng_l2cap_l2ca_get_info_req (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_l2ca_get_info_rsp (ng_l2cap_con_p, u_int32_t, u_int16_t,
struct mbuf *);
int ng_l2cap_l2ca_enable_clt (ng_l2cap_p, struct ng_mesg *);
#endif /* ndef _NETGRAPH_L2CAP_ULPI_H_ */

View File

@ -0,0 +1,182 @@
/*
* ng_l2cap_var.h
*
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_l2cap_var.h,v 1.13 2002/09/04 21:38:38 max Exp $
* $FreeBSD$
*/
#ifndef _NETGRAPH_L2CAP_VAR_H_
#define _NETGRAPH_L2CAP_VAR_H_ 1
/* MALLOC decalation */
#ifdef NG_SEPARATE_MALLOC
MALLOC_DECLARE(M_NETGRAPH_L2CAP);
#else
#define M_NETGRAPH_L2CAP M_NETGRAPH
#endif /* NG_SEPARATE_MALLOC */
/* Debug */
#define NG_L2CAP_ALERT if (l2cap->debug >= NG_L2CAP_ALERT_LEVEL) printf
#define NG_L2CAP_ERR if (l2cap->debug >= NG_L2CAP_ERR_LEVEL) printf
#define NG_L2CAP_WARN if (l2cap->debug >= NG_L2CAP_WARN_LEVEL) printf
#define NG_L2CAP_INFO if (l2cap->debug >= NG_L2CAP_INFO_LEVEL) printf
/* Wrapper around m_pullup */
#define NG_L2CAP_M_PULLUP(m, s) \
do { \
if ((m)->m_len < (s)) \
(m) = m_pullup((m), (s)); \
if ((m) == NULL) \
NG_L2CAP_ALERT("%s: %s - m_pullup(%d) failed\n", \
__func__, NG_NODE_NAME(l2cap->node), (s)); \
} while (0)
/*
* L2CAP signaling command ident's are assigned relative to the connection,
* because there is only one signaling channel (cid == 0x01) for every
* connection. So up to 254 (0xff - 0x01) L2CAP commands can be pending at the
* same time for the same connection.
*/
#define NG_L2CAP_NULL_IDENT 0x00 /* DO NOT USE THIS IDENT */
#define NG_L2CAP_FIRST_IDENT 0x01 /* dynamically alloc. (start) */
#define NG_L2CAP_LAST_IDENT 0xff /* dynamically alloc. (end) */
/*
* L2CAP (Node private)
*/
struct ng_l2cap_con;
struct ng_l2cap_chan;
typedef struct ng_l2cap {
node_p node; /* node ptr */
ng_l2cap_node_debug_ep debug; /* debug level */
ng_l2cap_node_flags_ep flags; /* L2CAP node flags */
bdaddr_t bdaddr; /* unit BDADDR */
u_int16_t pkt_size; /* max. ACL packet size */
u_int16_t num_pkts; /* out queue size */
hook_p hci; /* HCI downstream hook */
hook_p l2c; /* L2CAP upstream hook */
hook_p ctl; /* control hook */
LIST_HEAD(, ng_l2cap_con) con_list; /* ACL connections */
u_int16_t cid; /* last allocated CID */
LIST_HEAD(, ng_l2cap_chan) chan_list; /* L2CAP channels */
} ng_l2cap_t;
typedef ng_l2cap_t * ng_l2cap_p;
/*
* L2CAP connection descriptor
*/
struct ng_l2cap_cmd;
typedef struct ng_l2cap_con {
ng_l2cap_p l2cap; /* pointer to L2CAP */
u_int16_t state; /* ACL connection state */
bdaddr_t remote; /* remote unit address */
u_int16_t con_handle; /* ACL connection handle */
struct callout_handle con_timo; /* connection timeout */
u_int8_t ident; /* last allocated ident */
TAILQ_HEAD(, ng_l2cap_cmd) cmd_list; /* pending L2CAP cmds */
struct mbuf *tx_pkt; /* xmitted L2CAP packet */
int pending; /* num. of pending pkts */
struct mbuf *rx_pkt; /* received L2CAP packet */
int rx_pkt_len; /* packet len. so far */
LIST_ENTRY(ng_l2cap_con) next; /* link */
} ng_l2cap_con_t;
typedef ng_l2cap_con_t * ng_l2cap_con_p;
/*
* L2CAP channel descriptor
*/
typedef struct ng_l2cap_chan {
ng_l2cap_con_p con; /* pointer to connection */
u_int16_t state; /* channel state */
u_int8_t cfg_state; /* configuration state */
#define NG_L2CAP_CFG_IN (1 << 0) /* incoming cfg path done */
#define NG_L2CAP_CFG_OUT (1 << 1) /* outgoing cfg path done */
#define NG_L2CAP_CFG_BOTH (NG_L2CAP_CFG_IN|NG_L2CAP_CFG_OUT)
u_int8_t ident; /* last L2CAP req. ident */
u_int16_t psm; /* channel PSM */
u_int16_t scid; /* source channel ID */
u_int16_t dcid; /* destination channel ID */
u_int16_t imtu; /* incoming channel MTU */
ng_l2cap_flow_t iflow; /* incoming flow control */
u_int16_t omtu; /* outgoing channel MTU */
ng_l2cap_flow_t oflow; /* outgoing flow control */
u_int16_t flush_timo; /* flush timeout */
u_int16_t link_timo; /* link timeout */
LIST_ENTRY(ng_l2cap_chan) next; /* link */
} ng_l2cap_chan_t;
typedef ng_l2cap_chan_t * ng_l2cap_chan_p;
/*
* L2CAP command descriptor
*/
typedef struct ng_l2cap_cmd {
ng_l2cap_con_p con; /* L2CAP connection */
ng_l2cap_chan_p ch; /* L2CAP channel */
u_int16_t flags; /* command flags */
#define NG_L2CAP_CMD_PENDING (1 << 0) /* command is pending */
u_int8_t code; /* L2CAP command opcode */
u_int8_t ident; /* L2CAP command ident */
u_int32_t token; /* L2CA message token */
struct callout_handle timo; /* RTX/ERTX timeout */
struct mbuf *aux; /* optional data */
TAILQ_ENTRY(ng_l2cap_cmd) next; /* link */
} ng_l2cap_cmd_t;
typedef ng_l2cap_cmd_t * ng_l2cap_cmd_p;
#endif /* ndef _NETGRAPH_L2CAP_VAR_H_ */

View File

@ -0,0 +1,15 @@
$Id: TODO,v 1.4 2002/09/06 21:03:56 max Exp $
$FreeBSD$
FIXME/TODO list
1) Deal properly with "shutdown"s and hook "disconnect"s
How to let L2CAP node that user called "shutdown" on node or
have "disconnect"ed downstream hook. Should L2CAP node deal
with it?
2) Locking
It is OK to use mutexes, but is there a better way?

View File

@ -0,0 +1,258 @@
/*
* ng_btsocket.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ng_btsocket.c,v 1.20 2002/09/13 17:56:58 max Exp $
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/domain.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <bitstring.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include "ng_bluetooth.h"
#include "ng_hci.h"
#include "ng_l2cap.h"
#include "ng_btsocket.h"
#include "ng_btsocket_hci_raw.h"
#include "ng_btsocket_l2cap.h"
static int ng_btsocket_modevent (module_t, int, void *);
extern struct domain ng_btsocket_domain;
/*
* Bluetooth raw HCI sockets
*/
static struct pr_usrreqs ng_btsocket_hci_raw_usrreqs = {
ng_btsocket_hci_raw_abort, /* abort */
pru_accept_notsupp, /* accept */
ng_btsocket_hci_raw_attach, /* attach */
ng_btsocket_hci_raw_bind, /* bind */
ng_btsocket_hci_raw_connect, /* connect */
pru_connect2_notsupp, /* connect2 */
ng_btsocket_hci_raw_control, /* control */
ng_btsocket_hci_raw_detach, /* detach */
ng_btsocket_hci_raw_disconnect, /* disconnect */
pru_listen_notsupp, /* listen */
ng_btsocket_hci_raw_peeraddr, /* peeraddr */
pru_rcvd_notsupp, /* rcvd */
pru_rcvoob_notsupp, /* rcvoob */
ng_btsocket_hci_raw_send, /* send */
pru_sense_null, /* send */
NULL, /* shutdown */
ng_btsocket_hci_raw_sockaddr, /* sockaddr */
sosend,
soreceive,
sopoll
};
/*
* Bluetooth raw L2CAP sockets
*/
static struct pr_usrreqs ng_btsocket_l2cap_raw_usrreqs = {
ng_btsocket_l2cap_raw_abort, /* abort */
pru_accept_notsupp, /* accept */
ng_btsocket_l2cap_raw_attach, /* attach */
ng_btsocket_l2cap_raw_bind, /* bind */
ng_btsocket_l2cap_raw_connect, /* connect */
pru_connect2_notsupp, /* connect2 */
ng_btsocket_l2cap_raw_control, /* control */
ng_btsocket_l2cap_raw_detach, /* detach */
ng_btsocket_l2cap_raw_disconnect, /* disconnect */
pru_listen_notsupp, /* listen */
ng_btsocket_l2cap_raw_peeraddr, /* peeraddr */
pru_rcvd_notsupp, /* rcvd */
pru_rcvoob_notsupp, /* rcvoob */
ng_btsocket_l2cap_raw_send, /* send */
pru_sense_null, /* send */
NULL, /* shutdown */
ng_btsocket_l2cap_raw_sockaddr, /* sockaddr */
sosend,
soreceive,
sopoll
};
/*
* Bluetooth SEQPACKET L2CAP sockets
*/
static struct pr_usrreqs ng_btsocket_l2cap_usrreqs = {
ng_btsocket_l2cap_abort, /* abort */
ng_btsocket_l2cap_accept, /* accept */
ng_btsocket_l2cap_attach, /* attach */
ng_btsocket_l2cap_bind, /* bind */
ng_btsocket_l2cap_connect, /* connect */
pru_connect2_notsupp, /* connect2 */
ng_btsocket_l2cap_control, /* control */
ng_btsocket_l2cap_detach, /* detach */
ng_btsocket_l2cap_disconnect, /* disconnect */
ng_btsocket_l2cap_listen, /* listen */
ng_btsocket_l2cap_peeraddr, /* peeraddr */
pru_rcvd_notsupp, /* rcvd */
pru_rcvoob_notsupp, /* rcvoob */
ng_btsocket_l2cap_send, /* send */
pru_sense_null, /* send */
NULL, /* shutdown */
ng_btsocket_l2cap_sockaddr, /* sockaddr */
sosend,
soreceive,
sopoll
};
/*
* Definitions of protocols supported in the BLUETOOTH domain
*/
static struct protosw ng_btsocket_protosw[] = {
{
SOCK_RAW, /* protocol type */
&ng_btsocket_domain, /* backpointer to domain */
BLUETOOTH_PROTO_HCI, /* protocol */
PR_ATOMIC | PR_ADDR, /* flags */
NULL, NULL, NULL, /* input, output, ctlinput */
ng_btsocket_hci_raw_ctloutput, /* ctloutput */
NULL, /* ousrreq() */
ng_btsocket_hci_raw_init, /* init */
NULL, NULL, NULL, /* fasttimeo, slowtimo, drain */
&ng_btsocket_hci_raw_usrreqs, /* usrreq table (above) */
/* { NULL } */ /* pfh (protocol filter head?) */
},
{
SOCK_RAW, /* protocol type */
&ng_btsocket_domain, /* backpointer to domain */
BLUETOOTH_PROTO_L2CAP, /* protocol */
PR_ATOMIC | PR_ADDR, /* flags */
NULL, NULL, NULL, /* input, output, ctlinput */
NULL, /* ctloutput */
NULL, /* ousrreq() */
ng_btsocket_l2cap_raw_init, /* init */
NULL, NULL, NULL, /* fasttimeo, slowtimo, drain */
&ng_btsocket_l2cap_raw_usrreqs, /* usrreq table (above) */
/* { NULL } */ /* pfh (protocol filter head?) */
},
{
SOCK_SEQPACKET, /* protocol type */
&ng_btsocket_domain, /* backpointer to domain */
BLUETOOTH_PROTO_L2CAP, /* protocol */
PR_ATOMIC | PR_CONNREQUIRED, /* flags */
NULL, NULL, NULL, /* input, output, ctlinput */
ng_btsocket_l2cap_ctloutput, /* ctloutput */
NULL, /* ousrreq() */
ng_btsocket_l2cap_init, /* init */
NULL, NULL, NULL, /* fasttimeo, slowtimo, drain */
&ng_btsocket_l2cap_usrreqs, /* usrreq table (above) */
/* { NULL } */ /* pfh (protocol filter head?) */
}
};
#define ng_btsocket_protosw_size \
(sizeof(ng_btsocket_protosw)/sizeof(ng_btsocket_protosw[0]))
#define ng_btsocket_protosw_end \
&ng_btsocket_protosw[ng_btsocket_protosw_size]
/*
* BLUETOOTH domain
*/
struct domain ng_btsocket_domain = {
AF_BLUETOOTH, /* family */
"bluetooth", /* domain name */
NULL, /* init() */
NULL, /* externalize() */
NULL, /* dispose() */
ng_btsocket_protosw, /* protosw entry */
ng_btsocket_protosw_end, /* end of protosw entries */
NULL, /* next domain in list */
NULL, /* rtattach() */
0, /* arg to rtattach in bits */
0 /* maxrtkey */
};
/*
* Socket sysctl tree
*/
SYSCTL_NODE(_net_bluetooth_hci, OID_AUTO, sockets, CTLFLAG_RW,
0, "Bluetooth HCI sockets family");
SYSCTL_NODE(_net_bluetooth_l2cap, OID_AUTO, sockets, CTLFLAG_RW,
0, "Bluetooth L2CAP sockets family");
/*
* Module
*/
static moduledata_t ng_btsocket_mod = {
"ng_btsocket",
ng_btsocket_modevent,
NULL
};
DECLARE_MODULE(ng_btsocket, ng_btsocket_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_VERSION(ng_btsocket, NG_BLUETOOTH_VERSION);
MODULE_DEPEND(ng_btsocket, ng_bluetooth, NG_BLUETOOTH_VERSION,
NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION);
MODULE_DEPEND(ng_btsocket, netgraph, NG_ABI_VERSION,
NG_ABI_VERSION, NG_ABI_VERSION);
/*
* Handle loading and unloading for this node type.
* This is to handle auxiliary linkages (e.g protocol domain addition).
*/
static int
ng_btsocket_modevent(module_t mod, int event, void *data)
{
int error = 0;
switch (event) {
case MOD_LOAD:
net_add_domain(&ng_btsocket_domain);
break;
case MOD_UNLOAD:
/* XXX can't unload protocol domain yet */
error = EBUSY;
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
} /* ng_btsocket_modevent */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
# $FreeBSD$
SUBDIR= btsockstat
.include <bsd.subdir.mk>

View File

@ -0,0 +1,17 @@
# $Id: Makefile,v 1.1.1.1 2002/09/09 16:12:49 max Exp $
# $FreeBSD$
PROG= btsockstat
MAN1= btsockstat.1
DESTDIR= /usr/bin/
MANDIR= ../share/man/man
WARNS?= 2
CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include/
SRCS= btsockstat.c
DPADD= ${LIBKVM}
LDADD= -lkvm
.include <bsd.prog.mk>

View File

@ -0,0 +1,73 @@
.\" btsockstat.1
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: btsockstat.1,v 1.2 2002/11/12 17:08:34 max Exp $
.\" $FreeBSD$
.Dd August 31, 2002
.Dt BTSOCKSTAT 1
.Os
.Sh NAME
.Nm btsockstat
.Nd show Bluetooth sockets information
.Sh SYNOPSIS
.Nm
.Op Fl p Ar protocol
.Op Fl r
.Op Fl M Ar core
.Sh DESCRIPTION
The
.Nm
command symbolically displays the contents of various Bluetooth sockets
related data structures. There are few output formats, depending on the
options for the information presented.
.Nm
will print results to the standard output and error messages to the
standard error.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl p Ar protocol
Display a list of active sockets (protocol control blocks) for each
specified protocol. Supported protocols are:
.Cm hci_raw , l2cap_raw
and
.Cm l2cap .
.It Fl r
Display a list of active routing entries (if any) for specified protocol.
.It Fl M Ar core
Extract values associated with the name list from the specified core
instead of the default
.Pa /dev/kmem.
.El
.Sh BUGS
Most likely. Please report if found.
.Sh DIAGNOSTICS
.Ex -std
.Sh SEE ALSO
.Xr ng_btsocket 4
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View File

@ -0,0 +1,484 @@
/*
* btsockstat.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: btsockstat.c,v 1.2 2002/09/16 19:40:14 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/callout.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
#include <net/if_var.h>
#include <bitstring.h>
#include <err.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <ng_hci.h>
#include <ng_l2cap.h>
#include <ng_btsocket.h>
#include <ng_btsocket_hci_raw.h>
#include <ng_btsocket_l2cap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void hcirawpr (kvm_t *kvmd, u_long addr);
static void l2caprawpr (kvm_t *kvmd, u_long addr);
static void l2cappr (kvm_t *kvmd, u_long addr);
static void l2caprtpr (kvm_t *kvmd, u_long addr);
static kvm_t * kopen (char const *memf);
static int kread (kvm_t *kvmd, u_long addr, char *buffer, int size);
static void usage (void);
/*
* List of symbols
*/
static struct nlist nl[] = {
#define N_HCI_RAW 0
{ "_ng_btsocket_hci_raw_sockets" },
#define N_L2CAP_RAW 1
{ "_ng_btsocket_l2cap_raw_sockets" },
#define N_L2CAP 2
{ "_ng_btsocket_l2cap_sockets" },
#define N_L2CAP_RAW_RT 3
{ "_ng_btsocket_l2cap_raw_rt" },
#define N_L2CAP_RT 4
{ "_ng_btsocket_l2cap_rt" },
{ "" },
};
/*
* Main
*/
int
main(int argc, char *argv[])
{
int opt, proto = -1, route = 0;
kvm_t *kvmd = NULL;
char *memf = NULL;
while ((opt = getopt(argc, argv, "hM:p:r")) != -1) {
switch (opt) {
case 'M':
memf = optarg;
break;
case 'p':
if (strcasecmp(optarg, "hci_raw") == 0)
proto = N_HCI_RAW;
else if (strcasecmp(optarg, "l2cap_raw") == 0)
proto = N_L2CAP_RAW;
else if (strcasecmp(optarg, "l2cap") == 0)
proto = N_L2CAP;
else
usage();
/* NOT REACHED */
break;
case 'r':
route = 1;
break;
case 'h':
default:
usage();
/* NOT REACHED */
}
}
if (proto == N_HCI_RAW && route)
usage();
/* NOT REACHED */
kvmd = kopen(memf);
if (kvmd == NULL)
return (1);
switch (proto) {
case N_HCI_RAW:
hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
break;
case N_L2CAP_RAW:
if (route)
l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
else
l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
break;
case N_L2CAP:
if (route)
l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
else
l2cappr(kvmd, nl[N_L2CAP].n_value);
break;
default:
if (route) {
l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
} else {
hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
l2cappr(kvmd, nl[N_L2CAP].n_value);
}
break;
}
return (kvm_close(kvmd));
} /* main */
/*
* Print raw HCI sockets
*/
static void
hcirawpr(kvm_t *kvmd, u_long addr)
{
ng_btsocket_hci_raw_pcb_p this = NULL, next = NULL;
ng_btsocket_hci_raw_pcb_t pcb;
struct socket so;
int first = 1;
if (addr == 0)
return;
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
return;
for ( ; this != NULL; this = next) {
if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
return;
if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
return;
next = LIST_NEXT(&pcb, next);
if (first) {
first = 0;
fprintf(stdout,
"Active raw HCI sockets\n" \
"%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
"Socket",
"PCB",
"Flags",
"Recv-Q",
"Send-Q",
"Local address");
}
if (pcb.addr.hci_node[0] == 0) {
pcb.addr.hci_node[0] = '*';
pcb.addr.hci_node[1] = 0;
}
fprintf(stdout,
"%-8.8x %-8.8x %-6.6x %6d %6d %-16.16s\n",
(int) pcb.so,
(int) this,
pcb.flags,
so.so_rcv.sb_cc,
so.so_snd.sb_cc,
pcb.addr.hci_node);
}
} /* hcirawpr */
/*
* Print raw L2CAP sockets
*/
static void
l2caprawpr(kvm_t *kvmd, u_long addr)
{
ng_btsocket_l2cap_raw_pcb_p this = NULL, next = NULL;
ng_btsocket_l2cap_raw_pcb_t pcb;
struct socket so;
int first = 1;
char bdaddr[32];
if (addr == 0)
return;
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
return;
for ( ; this != NULL; this = next) {
if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
return;
if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
return;
next = LIST_NEXT(&pcb, next);
if (first) {
first = 0;
fprintf(stdout,
"Active raw L2CAP sockets\n" \
"%-8.8s %-8.8s %-6.6s %-6.6s %-18.18s\n",
"Socket",
"PCB",
"Recv-Q",
"Send-Q",
"Local address");
}
if (memcmp(&pcb.src, NG_HCI_BDADDR_ANY, sizeof(pcb.src)) == 0) {
bdaddr[0] = '*';
bdaddr[1] = 0;
} else
snprintf(bdaddr, sizeof(bdaddr),
"%02x:%02x:%02x:%02x:%02x:%02x",
pcb.src.b[5], pcb.src.b[4], pcb.src.b[3],
pcb.src.b[2], pcb.src.b[1], pcb.src.b[0]);
fprintf(stdout,
"%-8.8x %-8.8x %6d %6d %-18.18s\n",
(int) pcb.so,
(int) this,
so.so_rcv.sb_cc,
so.so_snd.sb_cc,
bdaddr);
}
} /* l2caprawpr */
/*
* Print L2CAP sockets
*/
static void
l2cappr(kvm_t *kvmd, u_long addr)
{
static char const * const states[] = {
/* NG_BTSOCKET_L2CAP_CLOSED */ "CLOSED",
/* NG_BTSOCKET_L2CAP_CONNECTING */ "CON",
/* NG_BTSOCKET_L2CAP_CONFIGURING */ "CONFIG",
/* NG_BTSOCKET_L2CAP_OPEN */ "OPEN",
/* NG_BTSOCKET_L2CAP_DISCONNECTING */ "DISCON"
};
#define state2str(x) \
(((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
ng_btsocket_l2cap_pcb_p this = NULL, next = NULL;
ng_btsocket_l2cap_pcb_t pcb;
struct socket so;
int first = 1;
char local[32], remote[32];
if (addr == 0)
return;
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
return;
for ( ; this != NULL; this = next) {
if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
return;
if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
return;
next = LIST_NEXT(&pcb, next);
if (first) {
first = 0;
fprintf(stdout,
"Active L2CAP sockets\n" \
"%-8.8s %-6.6s %-6.6s %-24.24s %-18.18s %-5.5s %s\n",
"PCB",
"Recv-Q",
"Send-Q",
"Local address/PSM",
"Foreign address",
"CID",
"State");
}
if (memcmp(&pcb.src, NG_HCI_BDADDR_ANY, sizeof(pcb.src)) == 0)
snprintf(local, sizeof(local), "*/%d", pcb.psm);
else
snprintf(local, sizeof(local),
"%02x:%02x:%02x:%02x:%02x:%02x/%d",
pcb.src.b[5], pcb.src.b[4], pcb.src.b[3],
pcb.src.b[2], pcb.src.b[1], pcb.src.b[0],
pcb.psm);
if (memcmp(&pcb.dst, NG_HCI_BDADDR_ANY, sizeof(pcb.dst)) == 0) {
remote[0] = '*';
remote[1] = 0;
} else
snprintf(remote, sizeof(remote),
"%02x:%02x:%02x:%02x:%02x:%02x",
pcb.dst.b[5], pcb.dst.b[4], pcb.dst.b[3],
pcb.dst.b[2], pcb.dst.b[1], pcb.dst.b[0]);
fprintf(stdout,
"%-8.8x %6d %6d %-24.24s %-18.18s %-5d %s\n",
(int) this,
so.so_rcv.sb_cc,
so.so_snd.sb_cc,
local,
remote,
pcb.cid,
(so.so_options & SO_ACCEPTCONN)?
"LISTEN" : state2str(pcb.state));
}
} /* l2cappr */
/*
* Print L2CAP routing table
*/
static void
l2caprtpr(kvm_t *kvmd, u_long addr)
{
ng_btsocket_l2cap_rtentry_p this = NULL, next = NULL;
ng_btsocket_l2cap_rtentry_t rt;
int first = 1;
char bdaddr[32];
if (addr == 0)
return;
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
return;
for ( ; this != NULL; this = next) {
if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
return;
next = LIST_NEXT(&rt, next);
if (first) {
first = 0;
fprintf(stdout,
"Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)? "raw " : "");
fprintf(stdout,
"%-8.8s %-8.8s %-18.18s\n", "RTentry",
"Hook",
"BD_ADDR");
}
if (memcmp(&rt.src, NG_HCI_BDADDR_ANY, sizeof(rt.src)) == 0) {
bdaddr[0] = '-';
bdaddr[1] = 0;
} else
snprintf(bdaddr, sizeof(bdaddr),
"%02x:%02x:%02x:%02x:%02x:%02x", rt.src.b[5], rt.src.b[4], rt.src.b[3],
rt.src.b[2], rt.src.b[1], rt.src.b[0]);
fprintf(stdout,
"%-8.8x %-8.8x %-18.18s\n",
(int) this,
(int) rt.hook,
bdaddr);
}
} /* l2caprtpr */
/*
* Open kvm
*/
static kvm_t *
kopen(char const *memf)
{
kvm_t *kvmd = NULL;
char errbuf[_POSIX2_LINE_MAX];
/*
* Discard setgid privileges if not the running kernel so that
* bad guys can't print interesting stuff from kernel memory.
*/
if (memf != NULL)
setgid(getgid());
kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
if (kvmd == NULL) {
warnx("kvm_openfiles: %s", errbuf);
return (NULL);
}
if (kvm_nlist(kvmd, nl) < 0) {
warnx("kvm_nlist: %s", kvm_geterr(kvmd));
goto fail;
}
if (nl[0].n_type == 0) {
warnx("kvm_nlist: no namelist");
goto fail;
}
return (kvmd);
fail:
kvm_close(kvmd);
return (NULL);
} /* kopen */
/*
* Read kvm
*/
static int
kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
{
if (kvmd == NULL || buffer == NULL)
return (-1);
if (kvm_read(kvmd, addr, buffer, size) != size) {
warnx("kvm_read: %s", kvm_geterr(kvmd));
return (-1);
}
return (0);
} /* kread */
/*
* Print usage and exit
*/
static void
usage(void)
{
fprintf(stdout, "Usage: btsockstat [-M core ] [-p proto] [-r]\n");
exit(255);
} /* usage */

View File

@ -0,0 +1,12 @@
# $Id$
# $FreeBSD$
SUBDIR= \
bt3cfw \
hccontrol \
hcseriald \
l2control \
l2ping
.include <bsd.subdir.mk>

View File

@ -0,0 +1,15 @@
# $Id: Makefile,v 1.1.1.1 2002/11/12 00:39:18 max Exp $
# $FreeBSD$
DESTDIR= /usr/sbin/
MANDIR= ../share/man/man
PROG= bt3cfw
MAN8= bt3cfw.8
WARNS?= 2
CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include
SRCS= bt3cfw.c
DPADD= ${LIBNETGRAPH}
LDADD= -lnetgraph
.include <bsd.prog.mk>

View File

@ -0,0 +1,69 @@
.\" bt3cfw.1
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: bt3cfw.8,v 1.1.1.1 2002/11/12 00:39:18 max Exp $
.\" $FreeBSD$
.Dd November 11, 2002
.Dt BT3CFW 8
.Os
.Sh NAME
.Nm BT3CFW
.Nd Firmware download utility for 3Com Bluetooth PC card driver
.Sh SYNOPSIS
.Nm
.Op Fl n Ar Netgraph node name
.Op Fl f Ar Firmware file name
.Sh DESCRIPTION
The
.Nm
utility connects to the specified Netgraph driver node of type
.Dv BTCCC
and downloads specified firmware file.
.Pp
Due to copyright issues I will no longer provide firmware with the card
driver. The firmware can be obtained from the Windows driver package that
can be downloaded from the 3COM web site at no charge. The firmware name
is BT3CPCC.BIN. I'm using original firmware that came with the card on CD-ROM.
.Bd -literal -offset indent
MD5 (BT3CPCC.BIN) = 36170fda56ea9fdbf1702c966f8a97f1
.Ed
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl n Ar Netgraph node name
Connect to the specified Netgraph driver node of type
.Dv BTCCC .
.It Fl f Ar Firmware file name
Specify firmware file name for download.
.El
.Sh BUGS
Please report if found.
.Sh DIAGNOSTICS
.Ex -std
.Sh SEE ALSO
.Xr ng_bt3c 4
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View File

@ -0,0 +1,227 @@
/*
* bt3cfw.c
*
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bt3cfw.c,v 1.1.1.1 2002/11/12 00:39:18 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <errno.h>
#include <netgraph.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "ng_bt3c.h"
#define BT3CFW_IDENT "bt3cfw"
#define BT3CFW_MAX_FIRMWARE_SIZE 0xffff
/* Convert hex ASCII to int4 */
static int
hexa2int4(const char *a)
{
if ('0' <= *a && *a <= '9')
return (*a - '0');
if ('A' <= *a && *a <= 'F')
return (*a - 'A' + 0xa);
if ('a' <= *a && *a <= 'f')
return (*a - 'a' + 0xa);
syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a);
exit(255);
}
/* Convert hex ASCII to int8 */
static int
hexa2int8(const char *a)
{
return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
}
/* Convert hex ASCII to int16 */
static int
hexa2int16(const char *a)
{
return ((hexa2int8(a) << 8) | hexa2int8(a + 2));
}
/* Convert hex ASCII to int32 */
static int
hexa2int32(const char *a)
{
return ((hexa2int16(a) << 16) | hexa2int16(a + 4));
}
/* Display usage() and exit */
static void
usage(void)
{
syslog(LOG_ERR, "Usage: %s -f FirmwareFile -n NodeName", BT3CFW_IDENT);
exit(255);
}
/* Main */
int
main(int argc, char *argv[])
{
FILE *firmware_file = NULL;
char buffer[80], path[NG_PATHLEN + 1],
*firmware_filename = NULL;
u_int8_t *firmware = NULL;
int firmware_size, opt, cs, ds;
memset(path, 0, sizeof(path));
openlog(BT3CFW_IDENT, LOG_NDELAY|LOG_PID|LOG_PERROR, LOG_USER);
while ((opt = getopt(argc, argv, "f:hn:")) != -1) {
switch (opt) {
case 'f':
firmware_filename = optarg;
break;
case 'n':
snprintf(path, sizeof(path), "%s:", optarg);
break;
case 'h':
default:
usage();
/* NOT REACHED */
}
}
if (firmware_filename == NULL || path[0] == 0)
usage();
/* NOT REACHED */
firmware = (u_int8_t *) calloc(BT3CFW_MAX_FIRMWARE_SIZE,
sizeof(u_int8_t));
if (firmware == NULL) {
syslog(LOG_ERR, "Could not allocate firmware buffer");
exit(255);
}
if ((firmware_file = fopen(firmware_filename, "r")) == NULL) {
syslog(LOG_ERR, "Could not open BT3C firmware file %s. %s (%d)",
firmware_filename, strerror(errno), errno);
exit(255);
}
firmware_size = 0;
while (fgets(buffer, sizeof(buffer), firmware_file)) {
int i, size, address, cs, fcs;
size = hexa2int8(buffer + 2);
address = hexa2int32(buffer + 4);
fcs = hexa2int8(buffer + 2 + size * 2);
if (buffer[1] == '3') {
ng_bt3c_firmware_block_ep *block = NULL;
u_int16_t *data = NULL;
block = (ng_bt3c_firmware_block_ep *)
(firmware + firmware_size);
firmware_size += sizeof(*block);
if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) {
syslog(LOG_ERR, "Could not add new firmware " \
"block. Firmware file %s is " \
"too big, firmware_size=%d",
firmware_filename,
firmware_size);
exit(255);
}
block->block_address = address;
block->block_size = (size - 4) / 2;
block->block_alignment = (block->block_size * 2) % 3;
if (block->block_alignment != 0)
block->block_alignment = 3 - block->block_alignment;
firmware_size += (block->block_size * 2);
firmware_size += block->block_alignment;
if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) {
syslog(LOG_ERR, "Could not add new firmware " \
"data. Firmware file %s is " \
"too big, firmware_size=%d",
firmware_filename,
firmware_size);
exit(255);
}
/* First part of the cheksum: size and address */
cs = 0;
for (i = 0; i < 5; i++)
cs += hexa2int8(buffer + 2 + i * 2);
/* Data + second part of the cheksum: data */
data = (u_int16_t *)(block + 1);
for (i = 0; i < block->block_size; i++) {
data[i] = hexa2int16(buffer + (i * 4) + 12);
cs += (((data[i] & 0xff00) >> 8) & 0xff);
cs += (data[i] & 0x00ff);
}
} else
for (cs = 0, i = 0; i < size; i++)
cs += hexa2int8(buffer + 2 + i * 2);
if (((cs + fcs) & 0xff) != 0xff) {
syslog(LOG_ERR, "Invalid firmware file %s. Checksum " \
"error, cs=%#x, fcs=%#x, checksum=%#x",
firmware_filename, (cs & 0xff), fcs,
((cs + fcs) & 0xff));
exit(255);
}
}
/* Send firmware to the card */
if (NgMkSockNode(NULL, &cs, &ds) < 0) {
syslog(LOG_ERR, "Could not create Netgraph socket. %s (%d)",
strerror(errno), errno);
exit(255);
}
if (NgSendMsg(cs, path, NGM_BT3C_COOKIE,
NGM_BT3C_NODE_DOWNLOAD_FIRMWARE,
(void const *) firmware, firmware_size) < 0) {
syslog(LOG_ERR, "Could not send Netgraph message. %s (%d)",
strerror(errno), errno);
exit(255);
}
free(firmware);
firmware = NULL;
return (0);
}

View File

@ -0,0 +1,14 @@
# $Id: Makefile,v 1.6 2002/09/06 18:52:41 max Exp $
# $FreeBSD$
DESTDIR= /usr/sbin/
MANDIR= ../share/man/man
PROG= hccontrol
MAN8= hccontrol.8
WARNS?= 2
CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include
SRCS= send_recv.c link_policy.c link_control.c \
host_controller_baseband.c info.c status.c node.c hccontrol.c \
util.c
.include <bsd.prog.mk>

View File

@ -0,0 +1,163 @@
.\" hccontrol.8
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: hccontrol.8,v 1.8 2002/11/12 22:33:17 max Exp $
.\" $FreeBSD$
.Dd June 14, 2002
.Dt HCCONTROL 8
.Os
.Sh NAME
.Nm hccontrol
.Nd HCI configuration utility
.Sh SYNOPSIS
.Nm
.Op Fl n Ar HCI node name
.Op Ar command
.Op Ar parameters ...
.Sh DESCRIPTION
The
.Nm
utility connects to the specified Netgraph node of type
.Em HCI
and attempts to send specified command to the HCI Netgraph node or to the
associated Bluetooth device.
.Nm
will print results to the standard output and error messages to
the standard error.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl n Ar HCI node name
Connect to the specified HCI Netgraph node.
.It command
One of the supported commands (see below). Special command
.Dq help
can be used to obtain the list of all supported commands. To get more
information about specific command use
.Dq help command .
.It parameters
One or more optional space separated command parameters.
.El
.Sh COMMANDS
The currently supported HCI commands in
.Nm
are:
.Pp
.Bd -literal -offset indent -compact
Inquiry
Create_Connection
Disconnect
Add_SCO_Connection
Change_Connection_Packet_Type
Remote_Name_Request
Read_Remote_Supported_Features
Read_Remote_Version_Information
Read_Clock_Offset
Role_Discovery
Switch_Role
Read_Link_Policy_Settings
Write_Link_Policy_Settings
Reset
Read_Pin_Type
Write_Pin_Type
Read_Stored_Link_Key
Write_Stored_Link_Key
Delete_Stored_Link_Key
Change_Local_Name
Read_Local_Name
Read_Connection_Accept_Timeout
Write_Connection_Accept_Timeout
Read_Page_Timeout
Write_Page_Timeout
Read_Scan_Enable
Write_Scan_Enable
Read_Page_Scan_Activity
Write_Page_Scan_Activity
Read_Inquiry_Scan_Activity
Write_Inquiry_Scan_Activity
Read_Authentication_Enable
Write_Authentication_Enable
Read_Encryption_Mode
Write_Encryption_Mode
Read_Class_Of_Device
Write_Class_Of_Device
Read_Voice_Settings
Write_Voice_Settings
Read_Number_Broadcast_Retransmissions
Write_Number_Broadcast_Retransmissions
Read_Hold_Mode_Activity
Write_Hold_Mode_Activity
Read_SCO_Flow_Control_Enable
Write_SCO_Flow_Control_Enable
Read_Link_Supervision_Timeout
Write_Link_Supervision_Timeout
Read_Local_Version_Information
Read_Local_Supported_Features
Read_Buffer_Size
Read_Country_Code
Read_BD_ADDR
Read_Failed_Contact_Counter
Reset_Failed_Contact_Counter
Get_Link_Quality
Read_RSSI
.Ed
.Pp
The currently supported node commands in
.Nm
are:
.Pp
.Bd -literal -offset indent -compact
Read_Node_State
Initialize
Read_Debug_Level
Write_Debug_Level
Read_Command_Timeout
Write_Command_Timeout
Read_Node_Buffer_Size
Read_Node_BD_ADDR
Read_Node_Features
Read_Node_Stat
Reset_Node_Stat
Flush_Neighbor_Cache
Read_Neighbor_Cache
Read_Connection_List
Read_Node_Link_Policy_Settings_Mask
Write_Node_Link_Policy_Settings_Mask
Read_Node_Packet_Mask
Write_Node_Packet_Mask
.Ed
.Pp
.Sh BUGS
Most likely. Please report if found.
.Sh DIAGNOSTICS
.Ex -std
.Sh SEE ALSO
.Xr netgraph 3 ,
.Xr netgraph 4 ,
.Xr ng_hci 4 ,
.Xr hcseriald 8
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View File

@ -0,0 +1,274 @@
/*
* hccontrol.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: hccontrol.c,v 1.11 2002/09/12 18:19:43 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <assert.h>
#include <bitstring.h>
#include <err.h>
#include <errno.h>
#include <ng_hci.h>
#include <ng_l2cap.h>
#include <ng_btsocket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "hccontrol.h"
/* Prototypes */
static int do_hci_command (char const *, int, char **);
static struct hci_command * find_hci_command (char const *, struct hci_command *);
static void print_hci_command (struct hci_command *);
static void usage (void);
/* Globals */
int verbose = 0;
int timeout;
/* Main */
int
main(int argc, char *argv[])
{
char *node = NULL;
int n;
/* Process command line arguments */
while ((n = getopt(argc, argv, "n:v")) != -1) {
switch (n) {
case 'n':
node = optarg;
break;
case 'v':
verbose = 1;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (*argv == NULL)
usage();
n = do_hci_command(node, argc, argv);
return (n);
} /* main */
/* Create socket and bind it */
static int
socket_open(char const *node)
{
struct sockaddr_hci addr;
struct ng_btsocket_hci_raw_filter filter;
int s, mib[4];
size_t size;
if (node == NULL)
usage();
s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
if (s < 0)
err(1, "Could not create socket");
memset(&addr, 0, sizeof(addr));
addr.hci_len = sizeof(addr);
addr.hci_family = AF_BLUETOOTH;
strncpy(addr.hci_node, node, sizeof(addr.hci_node));
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
err(2, "Could not bind socket, node=%s", node);
if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
err(3, "Could not connect socket, node=%s", node);
memset(&filter, 0, sizeof(filter));
bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_RESULT - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_CON_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_DISCON_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_RETURN_LINK_KEYS - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_CON_PKT_TYPE_CHANGED - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_ROLE_CHANGE - 1);
if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER,
(void * const) &filter, sizeof(filter)) < 0)
err(4, "Could not setsockopt()");
size = (sizeof(mib)/sizeof(mib[0]));
if (sysctlnametomib("net.bluetooth.hci.command_timeout",mib,&size) < 0)
err(5, "Could not sysctlnametomib()");
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]),
(void *) &timeout, &size, NULL, 0) < 0)
err(6, "Could not sysctl()");
timeout ++;
return (s);
} /* socket_open */
/* Execute commands */
static int
do_hci_command(char const *node, int argc, char **argv)
{
char *cmd = argv[0];
struct hci_command *c = NULL;
int s, e, help;
help = 0;
if (strcasecmp(cmd, "help") == 0) {
argc --;
argv ++;
if (argc <= 0) {
fprintf(stdout, "Supported commands:\n");
print_hci_command(link_control_commands);
print_hci_command(link_policy_commands);
print_hci_command(host_controller_baseband_commands);
print_hci_command(info_commands);
print_hci_command(status_commands);
print_hci_command(node_commands);
fprintf(stdout, "\nFor more information use " \
"'help command'\n");
return (OK);
}
help = 1;
cmd = argv[0];
}
c = find_hci_command(cmd, link_control_commands);
if (c != NULL)
goto execute;
c = find_hci_command(cmd, link_policy_commands);
if (c != NULL)
goto execute;
c = find_hci_command(cmd, host_controller_baseband_commands);
if (c != NULL)
goto execute;
c = find_hci_command(cmd, info_commands);
if (c != NULL)
goto execute;
c = find_hci_command(cmd, status_commands);
if (c != NULL)
goto execute;
c = find_hci_command(cmd, node_commands);
if (c == NULL) {
fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
return (ERROR);
}
execute:
if (!help) {
s = socket_open(node);
e = (c->handler)(s, -- argc, ++ argv);
close(s);
} else
e = USAGE;
switch (e) {
case OK:
case FAILED:
break;
case ERROR:
fprintf(stdout, "Could not execute command \"%s\". %s\n",
cmd, strerror(errno));
break;
case USAGE:
fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
break;
default: assert(0); break;
}
return (e);
} /* do_hci_command */
/* Try to find command in specified category */
static struct hci_command *
find_hci_command(char const *command, struct hci_command *category)
{
struct hci_command *c = NULL;
for (c = category; c->command != NULL; c++) {
char *c_end = strchr(c->command, ' ');
if (c_end != NULL) {
int len = c_end - c->command;
if (strncasecmp(command, c->command, len) == 0)
return (c);
} else if (strcasecmp(command, c->command) == 0)
return (c);
}
return (NULL);
} /* find_hci_command */
/* Try to find command in specified category */
static void
print_hci_command(struct hci_command *category)
{
struct hci_command *c = NULL;
for (c = category; c->command != NULL; c++)
fprintf(stdout, "\t%s\n", c->command);
} /* print_hci_command */
/* Usage */
static void
usage(void)
{
fprintf(stdout, "Usage: hccontrol -n HCI_node_name cmd [p1] [..]]\n");
exit(255);
} /* usage */

View File

@ -0,0 +1,75 @@
/*
* hccontrol.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: hccontrol.h,v 1.8 2002/09/12 18:19:43 max Exp $
* $FreeBSD$
*/
#ifndef _HCCONTROL_H_
#define _HCCONTROL_H_
#define OK 0 /* everything was OK */
#define ERROR 1 /* could not execute command */
#define FAILED 2 /* error was reported */
#define USAGE 3 /* invalid parameters */
struct hci_command {
char const *command;
char const *description;
int (*handler)(int, int, char **);
};
extern int timeout;
extern int verbose;
extern struct hci_command link_control_commands[];
extern struct hci_command link_policy_commands[];
extern struct hci_command host_controller_baseband_commands[];
extern struct hci_command info_commands[];
extern struct hci_command status_commands[];
extern struct hci_command node_commands[];
int hci_request (int, int, char const *, int, char *, int *);
int hci_simple_request (int, int, char *, int *);
int hci_send (int, char const *, int);
int hci_recv (int, char *, int *);
char const * const hci_link2str (int);
char const * const hci_pin2str (int);
char const * const hci_scan2str (int);
char const * const hci_encrypt2str (int, int);
char const * const hci_coding2str (int);
char const * const hci_vdata2str (int);
char const * const hci_hmode2str (int, char *, int);
char const * const hci_ver2str (int);
char const * const hci_manufacturer2str(int);
char const * const hci_features2str (u_int8_t *, char *, int);
char const * const hci_cc2str (int);
char const * const hci_con_state2str (int);
char const * const hci_status2str (int);
#endif /* _HCCONTROL_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,219 @@
/*
* info.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: info.c,v 1.7 2002/09/06 18:52:41 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/endian.h>
#include <errno.h>
#include <ng_hci.h>
#include <stdio.h>
#include <string.h>
#include "hccontrol.h"
/* Send Read_Local_Version_Information command to the unit */
static int
hci_read_local_version_information(int s, int argc, char **argv)
{
ng_hci_read_local_ver_rp rp;
int n;
n = sizeof(rp);
if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
NG_HCI_OCF_READ_LOCAL_VER), (char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
rp.manufacturer = le16toh(rp.manufacturer);
fprintf(stdout, "HCI version: %s [%#02x]\n",
hci_ver2str(rp.hci_version), rp.hci_version);
fprintf(stdout, "HCI revision: %#04x\n",
le16toh(rp.hci_revision));
fprintf(stdout, "LMP version: %#02x\n", rp.lmp_version);
fprintf(stdout, "LMP sub-version: %#04x\n",
le16toh(rp.lmp_subversion));
fprintf(stdout, "Manufacturer: %s [%#04x]\n",
hci_manufacturer2str(rp.manufacturer), rp.manufacturer);
return (OK);
} /* hci_read_local_version_information */
/* Send Read_Local_Supported_Features command to the unit */
static int
hci_read_local_supported_features(int s, int argc, char **argv)
{
ng_hci_read_local_features_rp rp;
int n;
char buffer[1024];
n = sizeof(rp);
if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
NG_HCI_OCF_READ_LOCAL_FEATURES),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Features: ");
for (n = 0; n < sizeof(rp.features); n++)
fprintf(stdout, "%#02x ", rp.features[n]);
fprintf(stdout, "\n%s\n", hci_features2str(rp.features,
buffer, sizeof(buffer)));
return (OK);
} /* hci_read_local_supported_features */
/* Sent Read_Buffer_Size command to the unit */
static int
hci_read_buffer_size(int s, int argc, char **argv)
{
ng_hci_read_buffer_size_rp rp;
int n;
n = sizeof(rp);
if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
NG_HCI_OCF_READ_BUFFER_SIZE),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Max. ACL packet size: %d bytes\n",
le16toh(rp.max_acl_size));
fprintf(stdout, "Number of ACL packets: %d\n",
le16toh(rp.num_acl_pkt));
fprintf(stdout, "Max. SCO packet size: %d bytes\n",
rp.max_sco_size);
fprintf(stdout, "Number of SCO packets: %d\n",
le16toh(rp.num_sco_pkt));
return (OK);
} /* hci_read_buffer_size */
/* Send Read_Country_Code command to the unit */
static int
hci_read_country_code(int s, int argc, char **argv)
{
ng_hci_read_country_code_rp rp;
int n;
n = sizeof(rp);
if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
NG_HCI_OCF_READ_COUNTRY_CODE),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Country code: %s [%#02x]\n",
hci_cc2str(rp.country_code), rp.country_code);
return (OK);
} /* hci_read_country_code */
/* Send Read_BD_ADDR command to the unit */
static int
hci_read_bd_addr(int s, int argc, char **argv)
{
ng_hci_read_bdaddr_rp rp;
int n;
n = sizeof(rp);
if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
NG_HCI_OCF_READ_BDADDR), (char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
rp.bdaddr.b[5], rp.bdaddr.b[4], rp.bdaddr.b[3],
rp.bdaddr.b[2], rp.bdaddr.b[1], rp.bdaddr.b[0]);
return (OK);
} /* hci_read_bd_addr */
struct hci_command info_commands[] = {
{
"read_local_version_information",
"\nThis command will read the values for the version information for the\n" \
"local Bluetooth unit.",
&hci_read_local_version_information
},
{
"read_local_supported_features",
"\nThis command requests a list of the supported features for the local\n" \
"unit. This command will return a list of the LMP features.",
&hci_read_local_supported_features
},
{
"read_buffer_size",
"\nThe Read_Buffer_Size command is used to read the maximum size of the\n" \
"data portion of HCI ACL and SCO Data Packets sent from the Host to the\n" \
"Host Controller.",
&hci_read_buffer_size
},
{
"read_country_code",
"\nThis command will read the value for the Country_Code return parameter.\n" \
"The Country_Code defines which range of frequency band of the ISM 2.4 GHz\n" \
"band will be used by the unit.",
&hci_read_country_code
},
{
"read_bd_addr",
"\nThis command will read the value for the BD_ADDR parameter. The BD_ADDR\n" \
"is a 48-bit unique identifier for a Bluetooth unit.",
&hci_read_bd_addr
},
{
NULL,
}};

View File

@ -0,0 +1,973 @@
/*
* link_control.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: link_control.c,v 1.12 2002/09/17 16:36:46 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/endian.h>
#include <errno.h>
#include <ng_hci.h>
#include <stdio.h>
#include <string.h>
#include "hccontrol.h"
static void hci_inquiry_response (int n, u_int8_t **b);
/* Send Inquiry command to the unit */
static int
hci_inquiry(int s, int argc, char **argv)
{
int n0, n1, n2, timo;
u_int8_t b[512];
ng_hci_inquiry_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* set defaults */
cp.lap[2] = 0x9e;
cp.lap[1] = 0x8b;
cp.lap[0] = 0x33;
cp.inquiry_length = 5;
cp.num_responses = 8;
/* parse command parameters */
switch (argc) {
case 3:
/* LAP */
if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3)
return (USAGE);
cp.lap[0] = (n0 & 0xff);
cp.lap[1] = (n1 & 0xff);
cp.lap[2] = (n2 & 0xff);
/* inquiry length (N * 1.28) sec, range 0x01 - 0x30 */
case 2:
if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x1 || n0 > 0x30)
return (USAGE);
cp.inquiry_length = (n0 & 0xff);
/* number of responses, range 0x00 - 0xff */
case 1:
if (sscanf(argv[2], "%d", &n0) != 1 || n0 > 0xff)
return (USAGE);
cp.num_responses = (n0 & 0xff);
/* use defaults */
case 0:
break;
default:
return (USAGE);
}
/* send request and expect status back */
n0 = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_INQUIRY), (char const *) &cp, sizeof(cp),
b, &n0) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
timo = timeout;
timeout = cp.inquiry_length * 1.28 + 1;
wait_for_more:
/* wait for inquiry events */
n0 = sizeof(b);
if (hci_recv(s, b, &n0) == ERROR) {
timeout = timo;
return (ERROR);
}
if (n0 < sizeof(*e)) {
timeout = timo;
errno = EIO;
return (ERROR);
}
switch (e->event) {
case NG_HCI_EVENT_INQUIRY_RESULT: {
ng_hci_inquiry_result_ep *ir =
(ng_hci_inquiry_result_ep *)(e + 1);
u_int8_t *r = (u_int8_t *)(ir + 1);
fprintf(stdout, "Inquiry result, num_responses=%d\n",
ir->num_responses);
for (n0 = 0; n0 < ir->num_responses; n0++)
hci_inquiry_response(n0, &r);
goto wait_for_more;
}
case NG_HCI_EVENT_INQUIRY_COMPL:
fprintf(stdout, "Inquiry complete. Status: %s [%#02x]\n",
hci_status2str(*(b + sizeof(*e))), *(b + sizeof(*e)));
break;
default:
goto wait_for_more;
}
timeout = timo;
return (OK);
} /* hci_inquiry */
/* Print Inquiry_Result event */
static void
hci_inquiry_response(int n, u_int8_t **b)
{
struct inquiry_response {
bdaddr_t bdaddr;
u_int8_t page_scan_rep_mode;
u_int8_t page_scan_period_mode;
u_int8_t page_scan_mode;
u_int8_t class[NG_HCI_CLASS_SIZE];
u_int16_t clock_offset;
} *ir = (struct inquiry_response *)(*b);
fprintf(stdout, "Inquiry result #%d\n", n);
fprintf(stdout, "\tBD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
ir->bdaddr.b[5], ir->bdaddr.b[4], ir->bdaddr.b[3],
ir->bdaddr.b[2], ir->bdaddr.b[1], ir->bdaddr.b[0]);
fprintf(stdout, "\tPage Scan Rep. Mode: %#02x\n",
ir->page_scan_rep_mode);
fprintf(stdout, "\tPage Scan Period Mode: %#02x\n",
ir->page_scan_period_mode);
fprintf(stdout, "\tPage Scan Mode: %#02x\n",
ir->page_scan_mode);
fprintf(stdout, "\tClass: %02x:%02x:%02x\n",
ir->class[2], ir->class[1], ir->class[0]);
fprintf(stdout, "\tClock offset: %#04x\n",
le16toh(ir->clock_offset));
*b += sizeof(*ir);
} /* hci_inquiry_response */
/* Send Create_Connection command to the unit */
static int
hci_create_connection(int s, int argc, char **argv)
{
int n0, n1, n2, n3, n4, n5;
char b[512];
ng_hci_create_con_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* Set defaults */
memset(&cp, 0, sizeof(cp));
cp.pkt_type = htole16( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
NG_HCI_PKT_DM5);
cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
cp.clock_offset = 0;
cp.accept_role_switch = 1;
/* parse command parameters */
switch (argc) {
case 6:
/* accept role switch */
if (sscanf(argv[2], "%d", &n0) != 1)
return (USAGE);
cp.accept_role_switch = n0 ? 1 : 0;
case 5:
/* clock offset */
if (sscanf(argv[2], "%d", &n0) != 1)
return (USAGE);
cp.clock_offset = (n0 & 0xffff);
cp.clock_offset = htole16(cp.clock_offset);
case 4:
/* page scan mode */
if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 3)
return (USAGE);
cp.page_scan_mode = (n0 & 0xff);
case 3:
/* page scan rep mode */
if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 2)
return (USAGE);
cp.page_scan_rep_mode = (n0 & 0xff);
case 2:
/* packet type */
if (sscanf(argv[1], "%x", &n0) != 1)
return (USAGE);
n0 &= ( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
NG_HCI_PKT_DM5);
if (n0 == 0)
return (USAGE);
cp.pkt_type = (n0 & 0xffff);
cp.pkt_type = htole16(cp.pkt_type);
case 1:
/* BD_ADDR */
if (sscanf(argv[0], "%x:%x:%x:%x:%x:%x",
&n5, &n4, &n3, &n2, &n1, &n0) != 6)
return (USAGE);
cp.bdaddr.b[0] = (n0 & 0xff);
cp.bdaddr.b[1] = (n1 & 0xff);
cp.bdaddr.b[2] = (n2 & 0xff);
cp.bdaddr.b[3] = (n3 & 0xff);
cp.bdaddr.b[4] = (n4 & 0xff);
cp.bdaddr.b[5] = (n5 & 0xff);
break;
default:
return (USAGE);
}
/* send request and expect status response */
n0 = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_CREATE_CON),
(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n0 = sizeof(b);
if (hci_recv(s, b, &n0) == ERROR)
return (ERROR);
if (n0 < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_CON_COMPL) {
ng_hci_con_compl_ep *ep = (ng_hci_con_compl_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
fprintf(stdout, "Connection handle: %d\n",
le16toh(ep->con_handle));
fprintf(stdout, "Encryption mode: %s [%d]\n",
hci_encrypt2str(ep->encryption_mode, 0),
ep->encryption_mode);
} else
goto again;
return (OK);
} /* hci_create_connection */
/* Send Disconnect command to the unit */
static int
hci_disconnect(int s, int argc, char **argv)
{
int n;
char b[512];
ng_hci_discon_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* Set defaults */
memset(&cp, 0, sizeof(cp));
cp.reason = 0x13;
/* parse command parameters */
switch (argc) {
case 2:
/* reason */
if (sscanf(argv[1], "%d", &n) != 1 || n <= 0x00 || n > 0xff)
return (USAGE);
cp.reason = (u_int8_t) (n & 0xff);
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request and expect status response */
n = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_DISCON),
(char const *) &cp, sizeof(cp), b, &n) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n = sizeof(b);
if (hci_recv(s, b, &n) == ERROR)
return (ERROR);
if (n < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_DISCON_COMPL) {
ng_hci_discon_compl_ep *ep = (ng_hci_discon_compl_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n",
le16toh(ep->con_handle));
fprintf(stdout, "Reason: %s [%#02x]\n",
hci_status2str(ep->reason), ep->reason);
} else
goto again;
return (OK);
} /* hci_diconnect */
/* Send Add_SCO_Connection command to the unit */
static int
hci_add_sco_connection(int s, int argc, char **argv)
{
int n;
char b[512];
ng_hci_add_sco_con_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* Set defaults */
memset(&cp, 0, sizeof(cp));
cp.pkt_type = htole16(NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);
/* parse command parameters */
switch (argc) {
case 2:
/* packet type */
if (sscanf(argv[0], "%x", &n) != 1)
return (USAGE);
n &= (NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);
if (n == 0)
return (USAGE);
cp.pkt_type = (u_int16_t) (n & 0x0fff);
cp.pkt_type = htole16(cp.pkt_type);
case 1:
/* acl connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request and expect status response */
n = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_ADD_SCO_CON),
(char const *) &cp, sizeof(cp), b, &n) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n = sizeof(b);
if (hci_recv(s, b, &n) == ERROR)
return (ERROR);
if (n < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_CON_COMPL) {
ng_hci_con_compl_ep *ep = (ng_hci_con_compl_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
fprintf(stdout, "Connection handle: %d\n",
le16toh(ep->con_handle));
fprintf(stdout, "Encryption mode: %s [%d]\n",
hci_encrypt2str(ep->encryption_mode, 0),
ep->encryption_mode);
} else
goto again;
return (OK);
} /* Add_SCO_Connection */
/* Send Change_Connection_Packet_Type command to the unit */
static int
hci_change_connection_packet_type(int s, int argc, char **argv)
{
int n;
char b[512];
ng_hci_change_con_pkt_type_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
switch (argc) {
case 2:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
/* packet type */
if (sscanf(argv[1], "%x", &n) != 1)
return (USAGE);
cp.pkt_type = (u_int16_t) (n & 0xffff);
cp.pkt_type = htole16(cp.pkt_type);
break;
default:
return (USAGE);
}
/* send request and expect status response */
n = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_CHANGE_CON_PKT_TYPE),
(char const *) &cp, sizeof(cp), b, &n) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n = sizeof(b);
if (hci_recv(s, b, &n) == ERROR)
return (ERROR);
if (n < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_CON_PKT_TYPE_CHANGED) {
ng_hci_con_pkt_type_changed_ep *ep =
(ng_hci_con_pkt_type_changed_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n",
le16toh(ep->con_handle));
fprintf(stdout, "Packet type: %#04x\n",
le16toh(ep->pkt_type));
} else
goto again;
return (OK);
} /* hci_change_connection_packet_type */
/* Send Remote_Name_Request command to the unit */
static int
hci_remote_name_request(int s, int argc, char **argv)
{
int n0, n1, n2, n3, n4, n5;
char b[512];
ng_hci_remote_name_req_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* parse command parameters */
switch (argc) {
case 4:
/* BD_ADDR */
if (sscanf(argv[0], "%x:%x:%x:%x:%x:%x",
&n5, &n4, &n3, &n2, &n1, &n0) != 6)
return (USAGE);
cp.bdaddr.b[0] = (n0 & 0xff);
cp.bdaddr.b[1] = (n1 & 0xff);
cp.bdaddr.b[2] = (n2 & 0xff);
cp.bdaddr.b[3] = (n3 & 0xff);
cp.bdaddr.b[4] = (n4 & 0xff);
cp.bdaddr.b[5] = (n5 & 0xff);
/* page_scan_rep_mode */
if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x02)
return (USAGE);
cp.page_scan_rep_mode = (n0 & 0xff);
/* page_scan_mode */
if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x03)
return (USAGE);
cp.page_scan_mode = (n0 & 0xff);
/* clock_offset */
if (sscanf(argv[3], "%x", &n0) != 1)
return (USAGE);
cp.clock_offset = (n0 & 0xffff);
cp.clock_offset = htole16(cp.clock_offset);
break;
default:
return (USAGE);
}
/* send request and expect status response */
n0 = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_REMOTE_NAME_REQ),
(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n0 = sizeof(b);
if (hci_recv(s, b, &n0) == ERROR)
return (ERROR);
if (n0 < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL) {
ng_hci_remote_name_req_compl_ep *ep =
(ng_hci_remote_name_req_compl_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
fprintf(stdout, "Name: %s\n", ep->name);
} else
goto again;
return (OK);
} /* hci_remote_name_request */
/* Send Read_Remote_Supported_Features command to the unit */
static int
hci_read_remote_supported_features(int s, int argc, char **argv)
{
int n;
char b[512];
ng_hci_read_remote_features_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
char buffer[1024];
/* parse command parameters */
switch (argc) {
case 1:
/* connecton handle */
if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request and expect status response */
n = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_READ_REMOTE_FEATURES),
(char const *) &cp, sizeof(cp), b, &n) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n = sizeof(b);
if (hci_recv(s, b, &n) == ERROR)
return (ERROR);
if (n < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL) {
ng_hci_read_remote_features_compl_ep *ep =
(ng_hci_read_remote_features_compl_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n",
le16toh(ep->con_handle));
fprintf(stdout, "Features: ");
for (n = 0; n < sizeof(ep->features); n++)
fprintf(stdout, "%#02x ", ep->features[n]);
fprintf(stdout, "\n%s\n", hci_features2str(ep->features,
buffer, sizeof(buffer)));
} else
goto again;
return (OK);
} /* hci_read_remote_supported_features */
/* Send Read_Remote_Version_Information command to the unit */
static int
hci_read_remote_version_information(int s, int argc, char **argv)
{
int n;
char b[512];
ng_hci_read_remote_ver_info_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* parse command parameters */
switch (argc) {
case 1:
/* connecton handle */
if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request and expect status response */
n = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_READ_REMOTE_VER_INFO),
(char const *) &cp, sizeof(cp), b, &n) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n = sizeof(b);
if (hci_recv(s, b, &n) == ERROR)
return (ERROR);
if (n < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL) {
ng_hci_read_remote_ver_info_compl_ep *ep =
(ng_hci_read_remote_ver_info_compl_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
ep->manufacturer = le16toh(ep->manufacturer);
fprintf(stdout, "Connection handle: %d\n",
le16toh(ep->con_handle));
fprintf(stdout, "LMP version: %#02x\n", ep->lmp_version);
fprintf(stdout, "LMP sub-version: %#04x\n",
le16toh(ep->lmp_subversion));
fprintf(stdout, "Manufacturer: %s [%#04x]\n",
hci_manufacturer2str(ep->manufacturer),
ep->manufacturer);
} else
goto again;
return (OK);
} /* hci_read_remote_version_information */
/* Send Read_Clock_Offset command to the unit */
static int
hci_read_clock_offset(int s, int argc, char **argv)
{
int n;
char b[512];
ng_hci_read_clock_offset_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* parse command parameters */
switch (argc) {
case 1:
/* connecton handle */
if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request and expect status response */
n = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
NG_HCI_OCF_READ_CLOCK_OFFSET),
(char const *) &cp, sizeof(cp), b, &n) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n = sizeof(b);
if (hci_recv(s, b, &n) == ERROR)
return (ERROR);
if (n < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL) {
ng_hci_read_clock_offset_compl_ep *ep =
(ng_hci_read_clock_offset_compl_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n",
le16toh(ep->con_handle));
fprintf(stdout, "Clock offset: %#04x\n",
le16toh(ep->clock_offset));
} else
goto again;
return (OK);
} /* hci_read_clock_offset */
struct hci_command link_control_commands[] = {
{
"inquiry <LAP> <inquiry_length> <num_reponses>",
"\nThis command will cause the Bluetooth unit to enter Inquiry Mode.\n" \
"Inquiry Mode is used to discover other nearby Bluetooth units. The LAP\n" \
"input parameter contains the LAP from which the inquiry access code shall\n" \
"be derived when the inquiry procedure is made. The Inquiry_Length parameter\n"\
"specifies the total duration of the Inquiry Mode and, when this time\n" \
"expires, Inquiry will be halted. The Num_Responses parameter specifies the\n" \
"number of responses that can be received before the Inquiry is halted.\n\n" \
"\t<LAP> - xx:xx:xx; 9e:8b:33 (GIAC), 93:8b:00 (LDIAC)\n" \
"\t<inquiry_length> - dd; total length == dd * 1.28 sec\n" \
"\t<num_responses> - dd",
&hci_inquiry
},
{
"create_connection <BD_ADDR> <pkt> <rep_mode> <ps_mode> <clck_off> <role_sw>",
"" \
"\t<BD_ADDR> - remote unit address\n\n" \
"\t<pkt> - xxxx; packet type\n" \
"" \
"\t\tACL packets\n" \
"\t\t-----------\n" \
"\t\t0x0008 DM1\n" \
"\t\t0x0010 DH1\n" \
"\t\t0x0400 DM3\n" \
"\t\t0x0800 DH3\n" \
"\t\t0x4000 DM5\n" \
"\t\t0x8000 DH5\n\n" \
"" \
"\trep_mode - d; page scan repetition mode\n" \
"" \
"\t\tPage scan repetition modes\n" \
"\t\t--------------------------\n" \
"\t\t0 Page scan repetition mode 0\n" \
"\t\t1 Page scan repetition mode 1\n" \
"\t\t2 Page scan repetition mode 2\n" \
"\n" \
"\tps_mode - d; Page scan mode\n" \
"" \
"\t\tPage scan modes\n" \
"\t\t---------------\n" \
"\t\t0 Mandatory page scan mode\n" \
"\t\t1 Optional page scan mode1\n" \
"\t\t2 Optional page scan mode2\n" \
"\t\t3 Optional page scan mode3\n" \
"\n" \
"\tclck_off - dddd; clock offset. Use 0 if unknown\n\n" \
"\trole_sw - d; allow (1) or deny role switch\n",
&hci_create_connection
},
{
"disconnect <connection_handle> <reason>",
"\nThe Disconnection command is used to terminate an existing connection.\n" \
"The connection handle command parameter indicates which connection is to\n" \
"be disconnected. The Reason command parameter indicates the reason for\n" \
"ending the connection.\n\n" \
"\t<connection_handle> - dddd; connection handle\n" \
"\t<reason> - dd; reason; usually 19 (0x13) - user ended;\n" \
"\t also 0x05, 0x13-0x15, 0x1A, 0x29",
&hci_disconnect
},
{
"add_sco_connection <acl connection handle> <packet type>",
"This command will cause the link manager to create a SCO connection using\n" \
"the ACL connection specified by the connection handle command parameter.\n" \
"The Link Manager will determine how the new connection is established. This\n"\
"connection is determined by the current state of the device, its piconet,\n" \
"and the state of the device to be connected. The packet type command parameter\n" \
"specifies which packet types the Link Manager should use for the connection.\n"\
"The Link Manager must only use the packet type(s) specified by the packet\n" \
"type command parameter for sending HCI SCO data packets. Multiple packet\n" \
"types may be specified for the packet type command parameter by performing\n" \
"a bitwise OR operation of the different packet types. Note: An SCO connection\n" \
"can only be created when an ACL connection already exists and when it is\n" \
"not put in park mode.\n\n" \
"\t<connection_handle> - dddd; ACL connection handle\n" \
"\t<packet_type> - xxxx; packet type\n" \
"" \
"\t\tSCO packets\n" \
"\t\t-----------\n" \
"\t\t0x0020 HV1\n" \
"\t\t0x0040 HV2\n" \
"\t\t0x0080 HV3\n",
&hci_add_sco_connection
},
{
"change_connection_packet_type <connection_hande> <packet_type>",
"The Change_Connection_Packet_Type command is used to change which packet\n" \
"types can be used for a connection that is currently established. This\n" \
"allows current connections to be dynamically modified to support different\n" \
"types of user data. The Packet_Type command parameter specifies which\n" \
"packet types the Link Manager can use for the connection. Multiple packet\n" \
"types may be specified for the Packet_Type command parameter by bitwise OR\n" \
"operation of the different packet types.\n\n" \
"\t<connection_handle> - dddd; connection handle\n" \
"\t<packet_type> - xxxx; packet type mask\n" \
"" \
"\t\tACL packets\n" \
"\t\t-----------\n" \
"\t\t0x0008 DM1\n" \
"\t\t0x0010 DH1\n" \
"\t\t0x0400 DM3\n" \
"\t\t0x0800 DH3\n" \
"\t\t0x4000 DM5\n" \
"\t\t0x8000 DH5\n\n" \
"" \
"\t\tSCO packets\n" \
"\t\t-----------\n" \
"\t\t0x0020 HV1\n" \
"\t\t0x0040 HV2\n" \
"\t\t0x0080 HV3\n" \
"",
&hci_change_connection_packet_type
},
{
"remote_name_request <bdaddr> <ps_rep_mode> <ps_mode> <clock_offset>",
"\nThe Remote_Name_Request command is used to obtain the user-friendly\n" \
"name of another Bluetooth unit.\n\n" \
"\t<bdaddr> - xx:xx:xx:xx:xx:xx remote unit BD_ADDR\n" \
"\t<ps_rep_mode> - dd; page scan repetition mode [0-2]\n" \
"\t<ps_mode> - dd; page scan mode [0-3]\n" \
"\t<clock_offset> - xxxx; clock offset [0 - 0xffff]",
&hci_remote_name_request
},
{
"read_remote_supported_features <connection_handle>",
"\nThis command requests a list of the supported features for the remote\n" \
"unit identified by the connection handle parameter. The connection handle\n" \
"must be a connection handle for an ACL connection.\n\n" \
"\t<connection_handle> - dddd; connection handle",
&hci_read_remote_supported_features
},
{
"read_remote_version_information <connection_handle>",
"\nThis command will obtain the values for the version information for the\n" \
"remote Bluetooth unit identified by the connection handle parameter. The\n" \
"connection handle must be a connection handle for an ACL connection.\n\n" \
"\t<conneciton_handle> - dddd; connection handle",
&hci_read_remote_version_information
},
{
"read_clock_offset <connection_handle>",
"\nThis command allows the Host to read clock offset to remote unit.\n" \
"\t<conneciton_handle> - dddd; connection handle",
&hci_read_clock_offset
},
{
NULL,
}};

View File

@ -0,0 +1,310 @@
/*
* link_policy.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: link_policy.c,v 1.3 2002/09/17 16:33:44 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/endian.h>
#include <errno.h>
#include <ng_hci.h>
#include <stdio.h>
#include "hccontrol.h"
/* Send Role Discovery to the unit */
static int
hci_role_discovery(int s, int argc, char **argv)
{
ng_hci_role_discovery_cp cp;
ng_hci_role_discovery_rp rp;
int n;
/* parse command parameters */
switch (argc) {
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
NG_HCI_OCF_ROLE_DISCOVERY),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
fprintf(stdout, "Role: %s [%#x]\n",
(rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role);
return (OK);
} /* hci_role_discovery */
/* Send Swith Role to the unit */
static int
hci_switch_role(int s, int argc, char **argv)
{
int n0, n1, n2, n3, n4, n5;
char b[512];
ng_hci_switch_role_cp cp;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b;
/* parse command parameters */
switch (argc) {
case 2:
/* bdaddr */
if (sscanf(argv[0], "%x:%x:%x:%x:%x:%x",
&n5, &n4, &n3, &n2, &n1, &n0) != 6)
return (USAGE);
cp.bdaddr.b[0] = n0 & 0xff;
cp.bdaddr.b[1] = n1 & 0xff;
cp.bdaddr.b[2] = n2 & 0xff;
cp.bdaddr.b[3] = n3 & 0xff;
cp.bdaddr.b[4] = n4 & 0xff;
cp.bdaddr.b[5] = n5 & 0xff;
/* role */
if (sscanf(argv[1], "%d", &n0) != 1)
return (USAGE);
cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER;
break;
default:
return (USAGE);
}
/* send request and expect status response */
n0 = sizeof(b);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
NG_HCI_OCF_SWITCH_ROLE),
(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
return (ERROR);
if (*b != 0x00)
return (FAILED);
/* wait for event */
again:
n0 = sizeof(b);
if (hci_recv(s, b, &n0) == ERROR)
return (ERROR);
if (n0 < sizeof(*e)) {
errno = EIO;
return (ERROR);
}
if (e->event == NG_HCI_EVENT_ROLE_CHANGE) {
ng_hci_role_change_ep *ep = (ng_hci_role_change_ep *)(e + 1);
if (ep->status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(ep->status), ep->status);
return (FAILED);
}
fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
fprintf(stdout, "Role: %s [%#x]\n",
(ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave",
ep->role);
} else
goto again;
return (OK);
} /* hci_switch_role */
/* Send Read_Link_Policy_Settings command to the unit */
static int
hci_read_link_policy_settings(int s, int argc, char **argv)
{
ng_hci_read_link_policy_settings_cp cp;
ng_hci_read_link_policy_settings_rp rp;
int n;
/* parse command parameters */
switch (argc) {
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send request */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
NG_HCI_OCF_READ_LINK_POLICY_SETTINGS),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings));
return (OK);
} /* hci_read_link_policy_settings */
/* Send Write_Link_Policy_Settings command to the unit */
static int
hci_write_link_policy_settings(int s, int argc, char **argv)
{
ng_hci_write_link_policy_settings_cp cp;
ng_hci_write_link_policy_settings_rp rp;
int n;
/* parse command parameters */
switch (argc) {
case 2:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
/* link policy settings */
if (sscanf(argv[1], "%x", &n) != 1)
return (USAGE);
cp.settings = (u_int16_t) (n & 0x0ffff);
cp.settings = htole16(cp.settings);
break;
default:
return (USAGE);
}
/* send request */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
return (OK);
} /* hci_write_link_policy_settings */
struct hci_command link_policy_commands[] = {
{
"role_discovery <conection_handle>",
"\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \
"which role the device is performing for a particular Connection Handle.\n" \
"The connection handle must be a connection handle for an ACL connection.\n\n" \
"\t<connection_handle> - dddd; connection handle",
&hci_role_discovery
},
{
"switch_role <bdaddr> <role>",
"\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \
"current role the device is performing for a particular connection with\n" \
"another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\
"for which connection the role switch is to be performed. The Role indicates\n"\
"the requested new role that the local device performs. Note: the BD_ADDR\n" \
"command parameter must specify a Bluetooth device for which a connection\n"
"already exists.\n\n" \
"\t<bdaddr> - xx:xx:xx:xx:xx:xx; device bdaddr\n" \
"\t<role> - dd; role; 0 - Master, 1 - Slave",
&hci_switch_role
},
{
"read_link_policy_settings <connection_handle>",
"\nThis command will read the Link Policy setting for the specified connection\n"\
"handle. The link policy settings parameter determines the behavior of the\n" \
"local Link Manager when it receives a request from a remote device or it\n" \
"determines itself to change the master-slave role or to enter the hold,\n" \
"sniff, or park mode. The local Link Manager will automatically accept or\n" \
"reject such a request from the remote device, and may even autonomously\n" \
"request itself, depending on the value of the link policy settings parameter\n"\
"for the corresponding connection handle. The connection handle must be a\n" \
"connection handle for an ACL connection.\n\n" \
"\t<connection_handle> - dddd; connection handle",
&hci_read_link_policy_settings
},
{
"write_link_policy_settings <connection_handle> <settings>",
"\nThis command will write the Link Policy setting for the specified connection\n"\
"handle. The link policy settings parameter determines the behavior of the\n" \
"local Link Manager when it receives a request from a remote device or it\n" \
"determines itself to change the master-slave role or to enter the hold,\n" \
"sniff, or park mode. The local Link Manager will automatically accept or\n" \
"reject such a request from the remote device, and may even autonomously\n" \
"request itself, depending on the value of the link policy settings parameter\n"\
"for the corresponding connection handle. The connection handle must be a\n" \
"connection handle for an ACL connection. Multiple Link Manager policies may\n"\
"be specified for the link policy settings parameter by performing a bitwise\n"\
"OR operation of the different activity types.\n\n" \
"\t<connection_handle> - dddd; connection handle\n" \
"\t<settings> - xxxx; settings\n" \
"\t\t0x0000 - Disable All LM Modes (Default)\n" \
"\t\t0x0001 - Enable Master Slave Switch\n" \
"\t\t0x0002 - Enable Hold Mode\n" \
"\t\t0x0004 - Enable Sniff Mode\n" \
"\t\t0x0008 - Enable Park Mode\n",
&hci_write_link_policy_settings
},
{
NULL,
}};

View File

@ -0,0 +1,518 @@
/*
* node.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: node.c,v 1.8 2002/11/12 22:33:17 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <bitstring.h>
#include <errno.h>
#include <ng_hci.h>
#include <ng_l2cap.h>
#include <ng_btsocket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hccontrol.h"
/* Send Read_Node_State command to the node */
static int
hci_read_node_state(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_state r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nState: %#x\n", r.hci_node, r.state);
return (OK);
} /* hci_read_node_state */
/* Send Intitialize command to the node */
static int
hci_node_initialize(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_init r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_INIT, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_node_initialize */
/* Send Read_Debug_Level command to the node */
static int
hci_read_debug_level(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_debug r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nDebug level: %d\n", r.hci_node, r.debug);
return (OK);
} /* hci_read_debug_level */
/* Send Write_Debug_Level command to the node */
static int
hci_write_debug_level(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_debug r;
memset(&r, 0, sizeof(r));
switch (argc) {
case 1:
r.debug = atoi(argv[0]);
break;
default:
return (USAGE);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_write_debug_level */
/* Send Read_Node_Buffer_Size command to the node */
static int
hci_read_node_buffer_size(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_buffer r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\n",
r.hci_node);
fprintf(stdout, "Number of free command buffers: %d\n",
r.buffer.cmd_free);
fprintf(stdout, "Max. ACL packet size: %d\n",
r.buffer.acl_size);
fprintf(stdout, "Numbef of free ACL buffers: %d\n",
r.buffer.acl_free);
fprintf(stdout, "Total number of ACL buffers: %d\n",
r.buffer.acl_pkts);
fprintf(stdout, "Max. SCO packet size: %d\n",
r.buffer.sco_size);
fprintf(stdout, "Numbef of free SCO buffers: %d\n",
r.buffer.sco_free);
fprintf(stdout, "Total number of SCO buffers: %d\n",
r.buffer.sco_pkts);
return (OK);
} /* hci_read_node_buffer_size */
/* Send Read_Node_BD_ADDR command to the node */
static int
hci_read_node_bd_addr(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_bdaddr r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\n", r.hci_node);
fprintf(stdout, "BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
r.bdaddr.b[5], r.bdaddr.b[4], r.bdaddr.b[3],
r.bdaddr.b[2], r.bdaddr.b[1], r.bdaddr.b[0]);
return (OK);
} /* hci_read_node_bd_addr */
/* Send Read_Node_Features command to the node */
static int
hci_read_node_features(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_features r;
int n;
char buffer[1024];
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nFeatures: ", r.hci_node);
for (n = 0; n < sizeof(r.features)/sizeof(r.features[0]); n++)
fprintf(stdout, "%#02x ", r.features[n]);
fprintf(stdout, "\n%s\n", hci_features2str(r.features,
buffer, sizeof(buffer)));
return (OK);
} /* hci_read_node_features */
/* Send Read_Node_Stat command to the node */
static int
hci_read_node_stat(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_stat r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\n", r.hci_node);
fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent);
fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv);
fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv);
fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent);
fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv);
fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent);
fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv);
fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent);
return (OK);
} /* hci_read_node_stat */
/* Send Reset_Node_Stat command to the node */
static int
hci_reset_node_stat(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_reset_stat r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_reset_node_stat */
/* Send Flush_Neighbor_Cache command to the node */
static int
hci_flush_neighbor_cache(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_flush_neighbor_cache r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE,
&r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_flush_neighbor_cache */
/* Send Read_Neighbor_Cache command to the node */
static int
hci_read_neighbor_cache(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_neighbor_cache r;
int n, error = OK;
memset(&r, 0, sizeof(r));
r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM;
r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM,
sizeof(ng_hci_node_neighbor_cache_entry_ep));
if (r.entries == NULL) {
errno = ENOMEM;
return (ERROR);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r,
sizeof(r)) < 0) {
error = ERROR;
goto out;
}
fprintf(stdout, "Neighbor cache for the node: %s\n", r.hci_node);
fprintf(stdout,
"BD_ADDR " \
"Features " \
"Clock offset " \
"Page scan " \
"Rep. scan\n");
for (n = 0; n < r.num_entries; n++) {
fprintf(stdout,
"%02x:%02x:%02x:%02x:%02x:%02x " \
"%02x %02x %02x %02x %02x %02x %02x %02x " \
"%#12x " \
"%#9x " \
"%#9x\n",
r.entries[n].bdaddr.b[5], r.entries[n].bdaddr.b[4],
r.entries[n].bdaddr.b[3], r.entries[n].bdaddr.b[2],
r.entries[n].bdaddr.b[1], r.entries[n].bdaddr.b[0],
r.entries[n].features[0], r.entries[n].features[1],
r.entries[n].features[2], r.entries[n].features[3],
r.entries[n].features[4], r.entries[n].features[5],
r.entries[n].features[6], r.entries[n].features[7],
r.entries[n].clock_offset, r.entries[n].page_scan_mode,
r.entries[n].page_scan_rep_mode);
}
out:
free(r.entries);
return (error);
} /* hci_read_neightbor_cache */
/* Send Read_Connection_List command to the node */
static int
hci_read_connection_list(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_con_list r;
int n, error = OK;
memset(&r, 0, sizeof(r));
r.num_connections = NG_HCI_MAX_CON_NUM;
r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep));
if (r.connections == NULL) {
errno = ENOMEM;
return (ERROR);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
error = ERROR;
goto out;
}
fprintf(stdout, "Connections list for the node: %s\n", r.hci_node);
fprintf(stdout,
"Remote BD_ADDR " \
"Handle " \
"Type " \
"Mode " \
"Role " \
"Encrypt " \
"Pending " \
"Queue " \
"State\n");
for (n = 0; n < r.num_connections; n++) {
fprintf(stdout,
"%02x:%02x:%02x:%02x:%02x:%02x " \
"%6d " \
"%4.4s " \
"%4d " \
"%4.4s " \
"%7.7s " \
"%7d " \
"%5d " \
"%s\n",
r.connections[n].bdaddr.b[5],
r.connections[n].bdaddr.b[4],
r.connections[n].bdaddr.b[3],
r.connections[n].bdaddr.b[2],
r.connections[n].bdaddr.b[1],
r.connections[n].bdaddr.b[0],
r.connections[n].con_handle,
(r.connections[n].link_type == NG_HCI_LINK_ACL)?
"ACL" : "SCO",
r.connections[n].mode,
(r.connections[n].role == NG_HCI_ROLE_MASTER)?
"MAST" : "SLAV",
hci_encrypt2str(r.connections[n].encryption_mode, 1),
r.connections[n].pending,
r.connections[n].queue_len,
hci_con_state2str(r.connections[n].state));
}
out:
free(r.connections);
return (error);
} /* hci_read_connection_list */
/* Send Read_Link_Policy_Settings_Mask command to the node */
int
hci_read_link_policy_settings_mask(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_link_policy_mask r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nLink Policy Settings mask: %#04x\n",
r.hci_node, r.policy_mask);
return (OK);
} /* hci_read_link_policy_settings_mask */
/* Send Write_Link_Policy_Settings_Mask command to the node */
int
hci_write_link_policy_settings_mask(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_link_policy_mask r;
int m;
memset(&r, 0, sizeof(r));
switch (argc) {
case 1:
if (sscanf(argv[0], "%x", &m) != 1)
return (USAGE);
r.policy_mask = (m & 0xffff);
break;
default:
return (USAGE);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_write_link_policy_settings_mask */
/* Send Read_Packet_Mask command to the node */
int
hci_read_packet_mask(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_packet_mask r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "Node: %s\nPacket mask: %#04x\n",
r.hci_node, r.packet_mask);
return (OK);
} /* hci_read_packet_mask */
/* Send Write_Packet_Mask command to the node */
int
hci_write_packet_mask(int s, int argc, char **argv)
{
struct ng_btsocket_hci_raw_node_packet_mask r;
int m;
memset(&r, 0, sizeof(r));
switch (argc) {
case 1:
if (sscanf(argv[0], "%x", &m) != 1)
return (USAGE);
r.packet_mask = (m & 0xffff);
break;
default:
return (USAGE);
}
if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* hci_write_packet_mask */
struct hci_command node_commands[] = {
{
"read_node_state",
"Get HCI node state",
&hci_read_node_state
},
{
"initialize",
"Initialize HCI node",
&hci_node_initialize
},
{
"read_debug_level",
"Read HCI node debug level",
&hci_read_debug_level
},
{
"write_debug_level <level>",
"Write HCI node debug level",
&hci_write_debug_level
},
{
"read_node_buffer_size",
"Read HCI node buffer information",
&hci_read_node_buffer_size
},
{
"read_node_bd_addr",
"Read HCI node BD_ADDR",
&hci_read_node_bd_addr
},
{
"read_node_features",
"Read HCI node features",
&hci_read_node_features
},
{
"read_node_stat",
"Read HCI node statistic information",
&hci_read_node_stat
},
{
"reset_node_stat",
"Reset HCI node statistic information",
&hci_reset_node_stat
},
{
"flush_neighbor_cache",
"Flush HCI node neighbor cache",
&hci_flush_neighbor_cache
},
{
"read_neighbor_cache",
"Read HCI node neighbor cache",
&hci_read_neighbor_cache
},
{
"read_connection_list",
"Read connection list",
&hci_read_connection_list
},
{
"read_node_link_policy_settings_mask",
"Read Link Policy Settinngs mask for the node",
&hci_read_link_policy_settings_mask
},
{
"write_node_link_policy_settings_mask <policy_mask>",
"Write Link Policy Settinngs mask for the node. Policy mask - xxxx",
&hci_write_link_policy_settings_mask
},
{
"read_node_packet_mask",
"Read Packet mask for the node",
&hci_read_packet_mask
},
{
"write_node_packet_mask <packet_mask>",
"Write Packet mask for the node. Packet mask - xxxx",
&hci_write_packet_mask
},
{
NULL,
}};

View File

@ -0,0 +1,184 @@
/*
* send_recv.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: send_recv.c,v 1.4 2002/09/04 21:31:30 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/endian.h>
#include <assert.h>
#include <errno.h>
#include <ng_hci.h>
#include <string.h>
#include <unistd.h>
#include "hccontrol.h"
/* Send HCI request to the unit */
int
hci_request(int s, int opcode, char const *cp, int cp_size, char *rp, int *rp_size)
{
char buffer[512];
int n;
ng_hci_cmd_pkt_t *c = (ng_hci_cmd_pkt_t *) buffer;
ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) buffer;
assert(rp != NULL);
assert(*rp_size != NULL);
assert(*rp_size > 0);
c->type = NG_HCI_CMD_PKT;
c->opcode = (u_int16_t) opcode;
c->opcode = htole16(c->opcode);
if (cp != NULL) {
assert(0 < cp_size && cp_size <= NG_HCI_CMD_PKT_SIZE);
c->length = (u_int8_t) cp_size;
memcpy(buffer + sizeof(*c), cp, cp_size);
} else
c->length = 0;
if (hci_send(s, buffer, sizeof(*c) + cp_size) == ERROR)
return (ERROR);
again:
n = sizeof(buffer);
if (hci_recv(s, buffer, &n) == ERROR)
return (ERROR);
if (n < sizeof(*e)) {
errno = EMSGSIZE;
return (ERROR);
}
if (e->type != NG_HCI_EVENT_PKT) {
errno = EIO;
return (ERROR);
}
switch (e->event) {
case NG_HCI_EVENT_COMMAND_COMPL: {
ng_hci_command_compl_ep *cc =
(ng_hci_command_compl_ep *)(e + 1);
cc->opcode = le16toh(cc->opcode);
if (cc->opcode == 0x0000 || cc->opcode != opcode)
goto again;
n -= (sizeof(*e) + sizeof(*cc));
if (n < *rp_size)
*rp_size = n;
memcpy(rp, buffer + sizeof(*e) + sizeof(*cc), *rp_size);
} break;
case NG_HCI_EVENT_COMMAND_STATUS: {
ng_hci_command_status_ep *cs =
(ng_hci_command_status_ep *)(e + 1);
cs->opcode = le16toh(cs->opcode);
if (cs->opcode == 0x0000 || cs->opcode != opcode)
goto again;
*rp_size = 1;
*rp = cs->status;
} break;
default:
goto again;
}
return (OK);
} /* hci_request */
/* Send simple HCI request - Just HCI command packet (no parameters) */
int
hci_simple_request(int s, int opcode, char *rp, int *rp_size)
{
return (hci_request(s, opcode, NULL, 0, rp, rp_size));
} /* hci_simple_request */
/* Send HCI data to the unit */
int
hci_send(int s, char const *buffer, int size)
{
assert(buffer != NULL);
assert(size >= sizeof(ng_hci_cmd_pkt_t));
assert(size <= sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE);
if (send(s, buffer, size, 0) < 0)
return (ERROR);
return (OK);
} /* hci_send */
/* Receive HCI data from the unit */
int
hci_recv(int s, char *buffer, int *size)
{
struct timeval tv;
fd_set rfd;
int n;
assert(buffer != NULL);
assert(size != NULL);
assert(*size > sizeof(ng_hci_event_pkt_t));
again:
FD_ZERO(&rfd);
FD_SET(s, &rfd);
tv.tv_sec = timeout;
tv.tv_usec = 0;
n = select(s + 1, &rfd, NULL, NULL, &tv);
if (n <= 0) {
if (n < 0) {
if (errno == EINTR)
goto again;
} else
errno = ETIMEDOUT;
return (ERROR);
}
assert(FD_ISSET(s, &rfd));
n = recv(s, buffer, *size, 0);
if (n < 0)
return (ERROR);
*size = n;
return (OK);
} /* hci_recv */

View File

@ -0,0 +1,245 @@
/*
* status.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: status.c,v 1.2 2002/09/06 18:52:41 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/endian.h>
#include <errno.h>
#include <ng_hci.h>
#include <stdio.h>
#include "hccontrol.h"
/* Send Read_Failed_Contact_Counter command to the unit */
static int
hci_read_failed_contact_counter(int s, int argc, char **argv)
{
ng_hci_read_failed_contact_cntr_cp cp;
ng_hci_read_failed_contact_cntr_rp rp;
int n;
switch (argc) {
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send command */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
NG_HCI_OCF_READ_FAILED_CONTACT_CNTR),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
fprintf(stdout, "Failed contact counter: %d\n", le16toh(rp.counter));
return (OK);
} /* hci_read_failed_contact_counter */
/* Send Reset_Failed_Contact_Counter command to the unit */
static int
hci_reset_failed_contact_counter(int s, int argc, char **argv)
{
ng_hci_reset_failed_contact_cntr_cp cp;
ng_hci_reset_failed_contact_cntr_rp rp;
int n;
switch (argc) {
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send command */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
return (OK);
} /* hci_reset_failed_contact_counter */
/* Sent Get_Link_Quality command to the unit */
static int
hci_get_link_quality(int s, int argc, char **argv)
{
ng_hci_get_link_quality_cp cp;
ng_hci_get_link_quality_rp rp;
int n;
switch (argc) {
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send command */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
NG_HCI_OCF_GET_LINK_QUALITY),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
fprintf(stdout, "Link quality: %d\n", le16toh(rp.quality));
return (OK);
} /* hci_get_link_quality */
/* Send Read_RSSI command to the unit */
static int
hci_read_rssi(int s, int argc, char **argv)
{
ng_hci_read_rssi_cp cp;
ng_hci_read_rssi_rp rp;
int n;
switch (argc) {
case 1:
/* connection handle */
if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
return (USAGE);
cp.con_handle = (u_int16_t) (n & 0x0fff);
cp.con_handle = htole16(cp.con_handle);
break;
default:
return (USAGE);
}
/* send command */
n = sizeof(rp);
if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
NG_HCI_OCF_READ_RSSI),
(char const *) &cp, sizeof(cp),
(char *) &rp, &n) == ERROR)
return (ERROR);
if (rp.status != 0x00) {
fprintf(stdout, "Status: %s [%#02x]\n",
hci_status2str(rp.status), rp.status);
return (FAILED);
}
fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
fprintf(stdout, "RSSI: %d dB\n", (int) rp.rssi);
return (OK);
} /* hci_read_rssi */
struct hci_command status_commands[] = {
{
"read_failed_contact_counter <connection_handle>",
"\nThis command will read the value for the Failed_Contact_Counter\n" \
"parameter for a particular ACL connection to another device.\n\n" \
"\t<connection_handle> - dddd; ACL connection handle\n",
&hci_read_failed_contact_counter
},
{
"reset_failed_contact_counter <connection_handle>",
"\nThis command will reset the value for the Failed_Contact_Counter\n" \
"parameter for a particular ACL connection to another device.\n\n" \
"\t<connection_handle> - dddd; ACL connection handle\n",
&hci_reset_failed_contact_counter
},
{
"get_link_quality <connection_handle>",
"\nThis command will return the value for the Link_Quality for the\n" \
"specified ACL connection handle. This command will return a Link_Quality\n" \
"value from 0-255, which represents the quality of the link between two\n" \
"Bluetooth devices. The higher the value, the better the link quality is.\n" \
"Each Bluetooth module vendor will determine how to measure the link quality." \
"\n\n" \
"\t<connection_handle> - dddd; ACL connection handle\n",
&hci_get_link_quality
},
{
"read_rssi <connection_handle>",
"\nThis command will read the value for the difference between the\n" \
"measured Received Signal Strength Indication (RSSI) and the limits of\n" \
"the Golden Receive Power Range for a ACL connection handle to another\n" \
"Bluetooth device. Any positive RSSI value returned by the Host Controller\n" \
"indicates how many dB the RSSI is above the upper limit, any negative\n" \
"value indicates how many dB the RSSI is below the lower limit. The value\n" \
"zero indicates that the RSSI is inside the Golden Receive Power Range.\n\n" \
"\t<connection_handle> - dddd; ACL connection handle\n",
&hci_read_rssi
},
{
NULL,
}};

View File

@ -0,0 +1,350 @@
/*
* util.c
*
* Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: util.c,v 1.2 2002/09/12 18:19:43 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <string.h>
#define SIZE(x) (sizeof((x))/sizeof((x)[0]))
char const * const
hci_link2str(int link_type)
{
static char const * const t[] = {
/* NG_HCI_LINK_SCO */ "SCO",
/* NG_HCI_LINK_ACL */ "ACL"
};
return (link_type >= SIZE(t)? "?" : t[link_type]);
} /* hci_link2str */
char const * const
hci_pin2str(int type)
{
static char const * const t[] = {
/* 0x00 */ "Variable PIN",
/* 0x01 */ "Fixed PIN"
};
return (type >= SIZE(t)? "?" : t[type]);
} /* hci_pin2str */
char const * const
hci_scan2str(int scan)
{
static char const * const t[] = {
/* 0x00 */ "No Scan enabled",
/* 0x01 */ "Inquiry Scan enabled. Page Scan disabled",
/* 0x02 */ "Inquiry Scan disabled. Page Scan enabled",
/* 0x03 */ "Inquiry Scan enabled. Page Scan enabled"
};
return (scan >= SIZE(t)? "?" : t[scan]);
} /* hci_scan2str */
char const * const
hci_encrypt2str(int encrypt, int brief)
{
static char const * const t[] = {
/* 0x00 */ "Disabled",
/* 0x01 */ "Only for point-to-point packets",
/* 0x02 */ "Both point-to-point and broadcast packets"
};
static char const * const t1[] = {
/* NG_HCI_ENCRYPTION_MODE_NONE */ "NONE",
/* NG_HCI_ENCRYPTION_MODE_P2P */ "P2P",
/* NG_HCI_ENCRYPTION_MODE_ALL */ "ALL",
};
if (brief)
return (encrypt >= SIZE(t1)? "?" : t1[encrypt]);
return (encrypt >= SIZE(t)? "?" : t[encrypt]);
} /* hci_encrypt2str */
char const * const
hci_coding2str(int coding)
{
static char const * const t[] = {
/* 0x00 */ "Linear",
/* 0x01 */ "u-law",
/* 0x02 */ "A-law",
/* 0x03 */ "Reserved"
};
return (coding >= SIZE(t)? "?" : t[coding]);
} /* hci_coding2str */
char const * const
hci_vdata2str(int data)
{
static char const * const t[] = {
/* 0x00 */ "1's complement",
/* 0x01 */ "2's complement",
/* 0x02 */ "Sign-Magnitude",
/* 0x03 */ "Reserved"
};
return (data >= SIZE(t)? "?" : t[data]);
} /* hci_vdata2str */
char const * const
hci_hmode2str(int mode, char *buffer, int size)
{
static char const * const t[] = {
/* 0x01 */ "Suspend Page Scan ",
/* 0x02 */ "Suspend Inquiry Scan ",
/* 0x04 */ "Suspend Periodic Inquiries "
};
if (buffer != NULL && size > 0) {
int n;
memset(buffer, 0, size);
for (n = 0; n < SIZE(t); n++) {
int len = strlen(buffer);
if (len >= size)
break;
if (mode & (1 << n))
strncat(buffer, t[n], size - len);
}
}
return (buffer);
} /* hci_hmode2str */
char const * const
hci_ver2str(int ver)
{
static char const * const t[] = {
/* 0x00 */ "v1.0B",
/* 0x01 */ "v1.1"
};
return (ver >= SIZE(t)? "?" : t[ver]);
} /* hci_ver2str */
char const * const
hci_manufacturer2str(int m)
{
static char const * const t[] = {
/* 0000 */ "Ericsson Mobile Comunications",
/* 0001 */ "Nokia Mobile Phones",
/* 0002 */ "Intel Corp.",
/* 0003 */ "IBM Corp.",
/* 0004 */ "Toshiba Corp.",
/* 0005 */ "3Com",
/* 0006 */ "Microsoft",
/* 0007 */ "Lucent",
/* 0008 */ "Motorola",
/* 0009 */ "Infineon Technologies AG",
/* 0010 */ "Cambridge Silicon Radio",
/* 0011 */ "Silicon Wave",
/* 0012 */ "Digianswer A/S",
/* 0013 */ "Texas Instruments Inc.",
/* 0014 */ "Parthus Technologies Inc.",
/* 0015 */ "Broadcom Corporation",
/* 0016 */ "Mitel Semiconductor",
/* 0017 */ "Widcomm, Inc.",
/* 0018 */ "Telencomm Inc.",
/* 0019 */ "Atmel Corporation",
/* 0020 */ "Mitsubishi Electric Corporation",
/* 0021 */ "RTX Telecom A/S",
/* 0022 */ "KC Technology Inc.",
/* 0023 */ "Newlogic",
/* 0024 */ "Transilica, Inc.",
/* 0025 */ "Rohde & Schwartz GmbH & Co. KG",
/* 0026 */ "TTPCom Limited",
/* 0027 */ "Signia Technologies, Inc.",
/* 0028 */ "Conexant Systems Inc.",
/* 0029 */ "Qualcomm",
/* 0030 */ "Inventel",
/* 0031 */ "AVM Berlin",
/* 0032 */ "BandSpeed, Inc.",
/* 0033 */ "Mansella Ltd",
/* 0034 */ "NEC Corporation",
/* 0035 */ "WavePlus Technology Co., Ltd.",
/* 0036 */ "Alcatel",
/* 0037 */ "Philips Semiconductors",
/* 0038 */ "C Technologies",
/* 0039 */ "Open Interface",
/* 0040 */ "R F Micro Devices",
/* 0041 */ "Hitachi Ltd",
/* 0042 */ "Symbol Technologies, Inc.",
/* 0043 */ "Tenovis",
/* 0044 */ "Macronix International Co. Ltd.",
/* 0045 */ "GCT Semiconductor",
/* 0046 */ "Norwood Systems",
/* 0047 */ "MewTel Technology Inc."
};
return (m >= SIZE(t)? "?" : t[m]);
} /* hci_manufacturer2str */
char const * const
hci_features2str(u_int8_t *features, char *buffer, int size)
{
static char const * const t[][8] = {
{ /* byte 0 */
/* 0 */ "<3-Slot> ",
/* 1 */ "<5-Slot> ",
/* 2 */ "<Encryption> ",
/* 3 */ "<Slot offset> ",
/* 4 */ "<Timing accuracy> ",
/* 5 */ "<Switch> ",
/* 6 */ "<Hold mode> ",
/* 7 */ "<Sniff mode> "
},
{ /* byte 1 */
/* 0 */ "<Park mode> ",
/* 1 */ "<RSSI> ",
/* 2 */ "<Channel quality> ",
/* 3 */ "<SCO link> ",
/* 4 */ "<HV2 packets> ",
/* 5 */ "<HV3 packets> ",
/* 6 */ "<u-law log> ",
/* 7 */ "<A-law log> "
},
{ /* byte 2 */
/* 0 */ "<CVSD> ",
/* 1 */ "<Paging scheme> ",
/* 2 */ "<Power control> ",
/* 3 */ "<Transparent SCO data> ",
/* 4 */ "<Flow control lag (bit0)> ",
/* 5 */ "<Flow control lag (bit1)> ",
/* 6 */ "<Flow control lag (bit2)> ",
/* 7 */ "<Unknown2.7> "
}};
if (buffer != NULL && size > 0) {
int n, i, len0, len1;
memset(buffer, 0, size);
len1 = 0;
for (n = 0; n < SIZE(t); n++) {
for (i = 0; i < SIZE(t[n]); i++) {
len0 = strlen(buffer);
if (len0 >= size)
goto done;
if (features[n] & (1 << i)) {
if (len1 + strlen(t[n][i]) > 60) {
len1 = 0;
buffer[len0 - 1] = '\n';
}
len1 += strlen(t[n][i]);
strncat(buffer, t[n][i], size - len0);
}
}
}
}
done:
return (buffer);
} /* hci_features2str */
char const * const
hci_cc2str(int cc)
{
static char const * const t[] = {
/* 0x00 */ "North America, Europe, Japan",
/* 0x01 */ "France"
};
return (cc >= SIZE(t)? "?" : t[cc]);
} /* hci_cc2str */
char const * const
hci_con_state2str(int state)
{
static char const * const t[] = {
/* NG_HCI_CON_CLOSED */ "CLOSED",
/* NG_HCI_CON_W4_LP_CON_RSP */ "W4_LP_CON_RSP",
/* NG_HCI_CON_W4_CONN_COMPLETE */ "W4_CONN_COMPLETE",
/* NG_HCI_CON_OPEN */ "OPEN"
};
return (state >= SIZE(t)? "UNKNOWN" : t[state]);
} /* hci_con_state2str */
char const * const
hci_status2str(int status)
{
static char const * const t[] = {
/* 0x00 */ "No error",
/* 0x01 */ "Unknown HCI command",
/* 0x02 */ "No connection",
/* 0x03 */ "Hardware failure",
/* 0x04 */ "Page timeout",
/* 0x05 */ "Authentication failure",
/* 0x06 */ "Key missing",
/* 0x07 */ "Memory full",
/* 0x08 */ "Connection timeout",
/* 0x09 */ "Max number of connections",
/* 0x0a */ "Max number of SCO connections to a unit",
/* 0x0b */ "ACL connection already exists",
/* 0x0c */ "Command disallowed",
/* 0x0d */ "Host rejected due to limited resources",
/* 0x0e */ "Host rejected due to securiity reasons",
/* 0x0f */ "Host rejected due to remote unit is a personal unit",
/* 0x10 */ "Host timeout",
/* 0x11 */ "Unsupported feature or parameter value",
/* 0x12 */ "Invalid HCI command parameter",
/* 0x13 */ "Other end terminated connection: User ended connection",
/* 0x14 */ "Other end terminated connection: Low resources",
/* 0x15 */ "Other end terminated connection: About to power off",
/* 0x16 */ "Connection terminated by local host",
/* 0x17 */ "Repeated attempts",
/* 0x18 */ "Pairing not allowed",
/* 0x19 */ "Unknown LMP PDU",
/* 0x1a */ "Unsupported remote feature",
/* 0x1b */ "SCO offset rejected",
/* 0x1c */ "SCO interval rejected",
/* 0x1d */ "SCO air mode rejected",
/* 0x1e */ "Invalid LMP parameters",
/* 0x1f */ "Unspecified error",
/* 0x20 */ "Unsupported LMP parameter value",
/* 0x21 */ "Role change not allowed",
/* 0x22 */ "LMP response timeout",
/* 0x23 */ "LMP error transaction collision",
/* 0x24 */ "LMP PSU not allowed",
/* 0x25 */ "Encryption mode not acceptable",
/* 0x26 */ "Unit key used",
/* 0x27 */ "QoS is not supported",
/* 0x28 */ "Instant passed",
/* 0x29 */ "Paring with unit key not supported"
};
return (status >= SIZE(t)? "Unknown error" : t[status]);
} /* hci_status2str */

View File

@ -0,0 +1,17 @@
# $Id: Makefile,v 1.4 2002/09/04 21:29:58 max Exp $
# $FreeBSD$
DESTDIR= /usr/sbin/
MANDIR= ../share/man/man
PROG= hcseriald
MAN8= hcseriald.8
WARNS?= 2
CFLAGS+= -Wall -O2 -I../../../sys/netgraph/bluetooth/include
SRCS= hcseriald.c
DPADD= ${LIBNETGRAPH}
LDADD= -lnetgraph
.include <bsd.prog.mk>

View File

@ -0,0 +1,81 @@
.\" hcseriald.8
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: hcseriald.8,v 1.3 2002/11/09 19:16:50 max Exp $
.\" $FreeBSD$
.Dd June 14, 2002
.Dt HCSERIALD 8
.Os
.Sh NAME
.Nm hcseriald
.Nd supervise serial Bluetooth devices
.Sh SYNOPSIS
.Nm
.Op Fl f Ar device
.Op Fl n Ar node name
.Op Fl s Ar speed
.Op Fl d
.Sh DESCRIPTION
The
.Nm
handles serial Bluetooth devices. It does one simple thing. It opens
specified serial device, sets device parameters and pushes
.Em H4
line discipline.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl f Ar device
Callout device name. Example:
.Fl f
.Pa /dev/cuaa0 .
.It Fl n Ar node name
Set H4 Netgraph node name. Example:
.Fl n Ar sio0 .
.It Fl s Ar speed
Set serial device speed to
.Em speed .
Example:
.Fl s Ar 115200 .
.It Fl d
Do not disassociate from the controlling terminal, i.e. run in foreground.
.El
.Sh FILES
.Bl -tag -width /dev/consolectl -compact
.It Pa /var/run/hcserial.*.pid
process id of the currently running
.Nm
daemon. Where
.Dq *
is a H4 Netgraph node name.
.El
.Sh SEE ALSO
.Xr tty 4 ,
.Xr ng_h4 4 ,
.Xr ng_hci 4 ,
.Xr hccontrol 8
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View File

@ -0,0 +1,279 @@
/*
* hcseriald.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: hcseriald.c,v 1.4 2002/09/04 21:29:58 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netgraph/ng_message.h>
#include <netgraph.h>
#include <ng_h4.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <termios.h>
#include <unistd.h>
/* Prototypes */
static int open_device (char const *, speed_t, char const *);
static void sighandler (int);
static void usage ();
static char const * const hcseriald = "hcseriald";
static int done = 0;
int
main(int argc, char *argv[])
{
char *device = NULL, *name = NULL;
speed_t speed = 115200;
int n, detach = 1;
char p[FILENAME_MAX];
FILE *f = NULL;
struct sigaction sa;
/* Process command line arguments */
while ((n = getopt(argc, argv, "df:n:s:")) != -1) {
switch (n) {
case 'd':
detach = 0;
break;
case 'f':
device = optarg;
break;
case 'n':
name = optarg;
break;
case 's':
speed = atoi(optarg);
if (speed < 0)
usage(argv[0]);
break;
default:
usage(argv[0]);
break;
}
}
if (device == NULL || name == NULL)
usage(argv[0]);
openlog(hcseriald, LOG_PID | LOG_NDELAY, LOG_USER);
/* Open device */
n = open_device(device, speed, name);
if (detach) {
pid_t pid = fork();
if (pid == (pid_t) -1) {
syslog(LOG_ERR, "Could not fork(). %s (%d)",
strerror(errno), errno);
exit(1);
}
if (pid != 0)
exit(0);
if (daemon(0, 0) < 0) {
syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
strerror(errno), errno);
exit(1);
}
}
/* Write PID file */
snprintf(p, sizeof(p), "/var/run/%s.%s.pid", hcseriald, name);
f = fopen(p, "w");
if (f == NULL) {
syslog(LOG_ERR, "Could not fopen(%s). %s (%d)",
p, strerror(errno), errno);
exit(1);
}
fprintf(f, "%d", getpid());
fclose(f);
/* Install signal handler */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sighandler;
if (sigaction(SIGTERM, &sa, NULL) < 0) {
syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
strerror(errno), errno);
exit(1);
}
if (sigaction(SIGHUP, &sa, NULL) < 0) {
syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
strerror(errno), errno);
exit(1);
}
if (sigaction(SIGINT, &sa, NULL) < 0) {
syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
strerror(errno), errno);
exit(1);
}
/* Keep running */
while (!done)
select(0, NULL, NULL, NULL, NULL);
/* Remove PID file and close device */
unlink(p);
close(n);
closelog();
return (0);
} /* main */
/* Open terminal, set settings, push H4 line discipline and set node name */
static int
open_device(char const *device, speed_t speed, char const *name)
{
int fd, disc, cs, ds;
struct termios t;
struct nodeinfo ni;
struct ngm_name n;
char p[NG_NODELEN + 1];
/* Open terminal device and setup H4 line discipline */
fd = open(device, O_RDWR|O_NOCTTY);
if (fd < 0) {
syslog(LOG_ERR, "Could not open(%s). %s (%d)",
device, strerror(errno), errno);
exit(1);
}
tcflush(fd, TCIOFLUSH);
if (tcgetattr(fd, &t) < 0) {
syslog(LOG_ERR, "Could not tcgetattr(%s). %s (%d)",
device, strerror(errno), errno);
exit(1);
}
cfmakeraw(&t);
t.c_cflag |= CLOCAL; /* clocal */
t.c_cflag &= ~CSIZE; /* cs8 */
t.c_cflag |= CS8; /* cs8 */
t.c_cflag &= ~PARENB; /* -parenb */
t.c_cflag &= ~CSTOPB; /* -cstopb */
t.c_cflag |= CRTSCTS; /* crtscts */
if (tcsetattr(fd, TCSANOW, &t) < 0) {
syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
device, strerror(errno), errno);
exit(1);
}
tcflush(fd, TCIOFLUSH);
if (cfsetspeed(&t, speed) < 0) {
syslog(LOG_ERR, "Could not cfsetspeed(%s). %s (%d)",
device, strerror(errno), errno);
exit(1);
}
if (tcsetattr(fd, TCSANOW, &t) < 0) {
syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
device, strerror(errno), errno);
exit(1);
}
disc = H4DISC;
if (ioctl(fd, TIOCSETD, &disc) < 0) {
syslog(LOG_ERR, "Could not ioctl(%s, TIOCSETD, %d). %s (%d)",
device, disc, strerror(errno), errno);
exit(1);
}
/* Get default name of the Netgraph node */
memset(&ni, 0, sizeof(ni));
if (ioctl(fd, NGIOCGINFO, &ni) < 0) {
syslog(LOG_ERR, "Could not ioctl(%d, NGIOGINFO). %s (%d)",
fd, strerror(errno), errno);
exit(1);
}
/* Assign new name to the Netgraph node */
snprintf(p, sizeof(p), "%s:", ni.name);
snprintf(n.name, sizeof(n.name), "%s", name);
if (NgMkSockNode(NULL, &cs, &ds) < 0) {
syslog(LOG_ERR, "Could not NgMkSockNode(). %s (%d)",
strerror(errno), errno);
exit(1);
}
if (NgSendMsg(cs, p, NGM_GENERIC_COOKIE, NGM_NAME, &n, sizeof(n)) < 0) {
syslog(LOG_ERR, "Could not NgSendMsg(%d, %s, NGM_NAME, %s). " \
"%s (%d)", cs, p, n.name, strerror(errno), errno);
exit(1);
}
close(cs);
close(ds);
return (fd);
} /* open_device */
/* Signal handler */
static void
sighandler(int s)
{
done = 1;
} /* sighandler */
/* Usage */
static void
usage(void)
{
fprintf(stderr, "Usage: %s -f device -n node_name [-s speed -d]\n" \
"Where:\n" \
"\t-f device tty device name, ex. /dev/cuaa1\n" \
"\t-n node_name set Netgraph node name to node_name\n" \
"\t-s speed set tty speed, ex. 115200\n" \
"\t-d run in foreground\n",
hcseriald);
exit(255);
} /* usage */

View File

@ -0,0 +1,12 @@
# $Id: Makefile,v 1.3 2002/09/04 21:30:40 max Exp $
# $FreeBSD$
DESTDIR= /usr/sbin/
MANDIR= ../share/man/man
PROG= l2control
MAN8= l2control.8
WARNS?= 2
CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include
SRCS= l2cap.c l2control.c
.include <bsd.prog.mk>

View File

@ -0,0 +1,256 @@
/*
* l2cap.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: l2cap.c,v 1.6 2002/09/04 21:30:40 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <bitstring.h>
#include <errno.h>
#include <ng_hci.h>
#include <ng_l2cap.h>
#include <ng_btsocket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "l2control.h"
#define SIZE(x) (sizeof((x))/sizeof((x)[0]))
/* Send read_node_flags command to the node */
static int
l2cap_read_node_flags(int s, int argc, char **argv)
{
struct ng_btsocket_l2cap_raw_node_flags r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_L2CAP_NODE_GET_FLAGS, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n",
r.src.b[5], r.src.b[4], r.src.b[3],
r.src.b[2], r.src.b[1], r.src.b[0]);
fprintf(stdout, "Connectionless traffic flags:\n");
fprintf(stdout, "\tSDP: %s\n",
(r.flags & NG_L2CAP_CLT_SDP_DISABLED)? "disabled" : "enabled");
fprintf(stdout, "\tRFCOMM: %s\n",
(r.flags & NG_L2CAP_CLT_RFCOMM_DISABLED)? "disabled":"enabled");
fprintf(stdout, "\tTCP: %s\n",
(r.flags & NG_L2CAP_CLT_TCP_DISABLED)? "disabled" : "enabled");
return (OK);
} /* l2cap_read_node_flags */
/* Send read_debug_level command to the node */
static int
l2cap_read_debug_level(int s, int argc, char **argv)
{
struct ng_btsocket_l2cap_raw_node_debug r;
memset(&r, 0, sizeof(r));
if (ioctl(s, SIOC_L2CAP_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
return (ERROR);
fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n",
r.src.b[5], r.src.b[4], r.src.b[3],
r.src.b[2], r.src.b[1], r.src.b[0]);
fprintf(stdout, "Debug level: %d\n", r.debug);
return (OK);
} /* l2cap_read_debug_level */
/* Send write_debug_level command to the node */
static int
l2cap_write_debug_level(int s, int argc, char **argv)
{
struct ng_btsocket_l2cap_raw_node_debug r;
memset(&r, 0, sizeof(r));
switch (argc) {
case 1:
r.debug = atoi(argv[0]);
break;
default:
return (USAGE);
}
if (ioctl(s, SIOC_L2CAP_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
return (ERROR);
return (OK);
} /* l2cap_write_debug_level */
/* Send read_connection_list command to the node */
static int
l2cap_read_connection_list(int s, int argc, char **argv)
{
static char const * const state[] = {
/* NG_L2CAP_CON_CLOSED */ "CLOSED",
/* NG_L2CAP_W4_LP_CON_CFM */ "W4_LP_CON_CFM",
/* NG_L2CAP_CON_OPEN */ "OPEN"
};
#define con_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)])
struct ng_btsocket_l2cap_raw_con_list r;
int n, error = OK;
memset(&r, 0, sizeof(r));
r.num_connections = NG_L2CAP_MAX_CON_NUM;
r.connections = calloc(NG_L2CAP_MAX_CON_NUM,
sizeof(ng_l2cap_node_con_ep));
if (r.connections == NULL) {
errno = ENOMEM;
return (ERROR);
}
if (ioctl(s, SIOC_L2CAP_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
error = ERROR;
goto out;
}
fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n",
r.src.b[5], r.src.b[4], r.src.b[3],
r.src.b[2], r.src.b[1], r.src.b[0]);
fprintf(stdout, "L2CAP connections:\n");
fprintf(stdout,
"Remote BD_ADDR Handle Flags Pending State\n");
for (n = 0; n < r.num_connections; n++) {
fprintf(stdout,
"%02x:%02x:%02x:%02x:%02x:%02x " \
" %5d " \
"%2.2s %2.2s " \
"%7d " \
"%s\n",
r.connections[n].remote.b[5],
r.connections[n].remote.b[4],
r.connections[n].remote.b[3],
r.connections[n].remote.b[2],
r.connections[n].remote.b[1],
r.connections[n].remote.b[0],
r.connections[n].con_handle,
((r.connections[n].flags & NG_L2CAP_CON_TX)? "TX" : ""),
((r.connections[n].flags & NG_L2CAP_CON_RX)? "RX" : ""),
r.connections[n].pending,
con_state2str(r.connections[n].state));
}
out:
free(r.connections);
return (error);
} /* l2cap_read_connection_list */
/* Send read_channel_list command to the node */
static int
l2cap_read_channel_list(int s, int argc, char **argv)
{
static char const * const state[] = {
/* NG_L2CAP_CLOSED */ "CLOSED",
/* NG_L2CAP_W4_L2CAP_CON_RSP */ "W4_L2CAP_CON_RSP",
/* NG_L2CAP_W4_L2CA_CON_RSP */ "W4_L2CA_CON_RSP",
/* NG_L2CAP_CONFIG */ "CONFIG",
/* NG_L2CAP_OPEN */ "OPEN",
/* NG_L2CAP_W4_L2CAP_DISCON_RSP */ "W4_L2CAP_DISCON_RSP",
/* NG_L2CAP_W4_L2CA_DISCON_RSP */ "W4_L2CA_DISCON_RSP"
};
#define ch_state2str(x) ((x) >= SIZE(state)? "UNKNOWN" : state[(x)])
struct ng_btsocket_l2cap_raw_chan_list r;
int n, error = OK;
memset(&r, 0, sizeof(r));
r.num_channels = NG_L2CAP_MAX_CHAN_NUM;
r.channels = calloc(NG_L2CAP_MAX_CHAN_NUM,
sizeof(ng_l2cap_node_chan_ep));
if (r.channels == NULL) {
errno = ENOMEM;
return (ERROR);
}
if (ioctl(s, SIOC_L2CAP_NODE_GET_CHAN_LIST, &r, sizeof(r)) < 0) {
error = ERROR;
goto out;
}
fprintf(stdout, "BD_ADDR: %x:%x:%x:%x:%x:%x\n",
r.src.b[5], r.src.b[4], r.src.b[3],
r.src.b[2], r.src.b[1], r.src.b[0]);
fprintf(stdout, "L2CAP channels:\n");
fprintf(stdout,
"Remote BD_ADDR SCID/ DCID PSM IMTU/ OMTU State\n");
for (n = 0; n < r.num_channels; n++) {
fprintf(stdout,
"%02x:%02x:%02x:%02x:%02x:%02x " \
"%5d/%5d %5d " \
"%5d/%5d " \
"%s\n",
r.channels[n].remote.b[5], r.channels[n].remote.b[4],
r.channels[n].remote.b[3], r.channels[n].remote.b[2],
r.channels[n].remote.b[1], r.channels[n].remote.b[0],
r.channels[n].scid, r.channels[n].dcid,
r.channels[n].psm, r.channels[n].imtu,
r.channels[n].omtu,
ch_state2str(r.channels[n].state));
}
out:
free(r.channels);
return (error);
} /* l2cap_read_channel_list */
struct l2cap_command l2cap_commands[] = {
{
"read_node_flags",
"Get L2CAP node flags",
&l2cap_read_node_flags
},
{
"read_debug_level",
"Get L2CAP node debug level",
&l2cap_read_debug_level
},
{
"write_debug_level <level>",
"Set L2CAP node debug level",
&l2cap_write_debug_level
},
{
"read_connection_list",
"Read list of the L2CAP connections",
&l2cap_read_connection_list
},
{
"read_channel_list",
"Read list of the L2CAP channels",
&l2cap_read_channel_list
},
{
NULL,
}};

View File

@ -0,0 +1,84 @@
.\" l2control.8
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: l2control.8,v 1.4 2002/11/09 19:18:16 max Exp $
.\" $FreeBSD$
.Dd June 14, 2002
.Dt L2CONTROL 8
.Os
.Sh NAME
.Nm l2control
.Nd L2CAP configuration utility
.Sh SYNOPSIS
.Nm
.Op Fl a Ar local BD_ADDR
.Op Ar command
.Op Ar parameters ...
.Sh DESCRIPTION
The
.Nm
utility connects to the local device with specified BD_ADDR and attempts
to send specified command.
.Nm
will print results to the standard output and error messages to
the standard error.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl a Ar local BD_ADDR
Connect to the local device with specified BD_ADDR. Example:
.Fl a Ar 00:01:02:03:04:05 .
.It command
One of the supported commands (see below). Special command
.Dq help
can be used to obtain the list of all supported commands. To get more
information about specific command use
.Dq help command .
.It parameters
One or more optional space separated command parameters.
.El
.Sh COMMANDS
The currently supported node commands in
.Nm
are:
.Pp
.Bd -literal -offset indent -compact
Read_Node_Flags
Read_Debug_Level
Write_Debug_Level
Read_Connection_List
Read_Channel_List
.Ed
.Pp
.Sh DIAGNOSTICS
.Ex -std
.Sh SEE ALSO
.Xr netgraph 3 ,
.Xr netgraph 4 ,
.Xr ng_l2cap 4 ,
.Xr l2ping 8
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View File

@ -0,0 +1,226 @@
/*
* l2control.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: l2control.c,v 1.5 2002/09/04 21:30:40 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <bitstring.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <ng_hci.h>
#include <ng_l2cap.h>
#include <ng_btsocket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "l2control.h"
/* Prototypes */
static int do_l2cap_command (bdaddr_p, int, char **);
static struct l2cap_command * find_l2cap_command (char const *,
struct l2cap_command *);
static void print_l2cap_command (struct l2cap_command *);
static void usage (void);
/* Main */
int
main(int argc, char *argv[])
{
int n;
bdaddr_t bdaddr;
memset(&bdaddr, 0, sizeof(bdaddr));
/* Process command line arguments */
while ((n = getopt(argc, argv, "a:")) != -1) {
switch (n) {
case 'a': {
int a0, a1, a2, a3, a4, a5;
if (sscanf(optarg, "%x:%x:%x:%x:%x:%x",
&a5, &a4, &a3, &a2, &a1, &a0) != 6) {
usage();
break;
}
bdaddr.b[0] = (a0 & 0xff);
bdaddr.b[1] = (a1 & 0xff);
bdaddr.b[2] = (a2 & 0xff);
bdaddr.b[3] = (a3 & 0xff);
bdaddr.b[4] = (a4 & 0xff);
bdaddr.b[5] = (a5 & 0xff);
} break;
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (*argv == NULL)
usage();
return (do_l2cap_command(&bdaddr, argc, argv));
} /* main */
/* Execute commands */
static int
do_l2cap_command(bdaddr_p bdaddr, int argc, char **argv)
{
char *cmd = argv[0];
struct l2cap_command *c = NULL;
struct sockaddr_l2cap sa;
int s, e, help;
help = 0;
if (strcasecmp(cmd, "help") == 0) {
argc --;
argv ++;
if (argc <= 0) {
fprintf(stdout, "Supported commands:\n");
print_l2cap_command(l2cap_commands);
fprintf(stdout, "\nFor more information use " \
"'help command'\n");
return (OK);
}
help = 1;
cmd = argv[0];
}
c = find_l2cap_command(cmd, l2cap_commands);
if (c == NULL) {
fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
return (ERROR);
}
if (!help) {
if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0)
usage();
memset(&sa, 0, sizeof(sa));
sa.l2cap_len = sizeof(sa);
sa.l2cap_family = AF_BLUETOOTH;
memcpy(&sa.l2cap_bdaddr, bdaddr, sizeof(sa.l2cap_bdaddr));
s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP);
if (s < 0)
err(1, "Could not create socket");
if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
err(2,
"Could not bind socket, bdaddr=%x:%x:%x:%x:%x:%x",
sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
err(2,
"Could not connect socket, bdaddr=%x:%x:%x:%x:%x:%x",
sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
e = 0x0ffff;
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &e, sizeof(e)) < 0)
err(3, "Coult not setsockopt(RCVBUF, %d)", e);
e = (c->handler)(s, -- argc, ++ argv);
close(s);
} else
e = USAGE;
switch (e) {
case OK:
case FAILED:
break;
case ERROR:
fprintf(stdout, "Could not execute command \"%s\". %s\n",
cmd, strerror(errno));
break;
case USAGE:
fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
break;
default: assert(0); break;
}
return (e);
} /* do_l2cap_command */
/* Try to find command in specified category */
static struct l2cap_command *
find_l2cap_command(char const *command, struct l2cap_command *category)
{
struct l2cap_command *c = NULL;
for (c = category; c->command != NULL; c++) {
char *c_end = strchr(c->command, ' ');
if (c_end != NULL) {
int len = c_end - c->command;
if (strncasecmp(command, c->command, len) == 0)
return (c);
} else if (strcasecmp(command, c->command) == 0)
return (c);
}
return (NULL);
} /* find_l2cap_command */
/* Try to find command in specified category */
static void
print_l2cap_command(struct l2cap_command *category)
{
struct l2cap_command *c = NULL;
for (c = category; c->command != NULL; c++)
fprintf(stdout, "\t%s\n", c->command);
} /* print_l2cap_command */
/* Usage */
static void
usage(void)
{
fprintf(stdout, "Usage: l2control -a BD_ADDR cmd [p1] [..]]\n");
exit(255);
} /* usage */

View File

@ -0,0 +1,49 @@
/*
* l2control.h
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: l2control.h,v 1.2 2002/09/04 21:30:40 max Exp $
* $FreeBSD$
*/
#ifndef _L2CONTROL_H_
#define _L2CONTROL_H_
#define OK 0 /* everything was OK */
#define ERROR 1 /* could not execute command */
#define FAILED 2 /* error was reported */
#define USAGE 3 /* invalid parameters */
struct l2cap_command {
char const *command;
char const *description;
int (*handler)(int, int, char **);
};
extern struct l2cap_command l2cap_commands[];
#endif /* _L2CONTROL_H_ */

View File

@ -0,0 +1,12 @@
# $Id: Makefile,v 1.4 2002/09/04 21:28:05 max Exp $
# $FreeBSD$
DESTDIR= /usr/sbin/
MANDIR= ../share/man/man
PROG= l2ping
MAN8= l2ping.8
SRCS= l2ping.c
WARNS?= 2
CFLAGS+= -g -I../../../sys/netgraph/bluetooth/include
.include <bsd.prog.mk>

View File

@ -0,0 +1,87 @@
.\" l2ping.8
.\"
.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: l2ping.8,v 1.4 2002/11/09 19:20:09 max Exp $
.\" $FreeBSD$
.Dd June 14, 2002
.Dt L2PING 8
.Os
.Sh NAME
.Nm l2ping
.Nd send L2CAP ECHO_REQUEST to remote devices
.Sh SYNOPSIS
.Nm
.Op Fl a Ar remote BD_ADDR
.Op Fl S Ar source BD_ADDR
.Op Fl c Ar count
.Op Fl f
.Op Fl i Ar delay
.Op Fl s Ar size
.Sh DESCRIPTION
The
.Nm
uses L2CAP ECHO_REQUEST datagram to elicit a L2CAP ECHO_RESPONSE from a
remote device.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl a Ar remote BD_ADDR
Address of remote device to ping. Example:
.Fl a Ar 00:01:02:03:04:05 .
.It Fl S Ar source BD_ADDR
Send L2CAP ECHO_REQUEST from local device that has BD_ADDR. Example:
.Fl S Ar 00:05:04:03:02:01 .
.It Fl c Ar count
Number of packets to send. If this option is not specified,
.Nm
will operate until interrupted.
.It Fl f
.Dq Flood
ping, i.e. no delay between packets.
.It Fl i Ar wait
Wait
.Em wait
seconds between sending each packet. The default is to wait for one
second between each packet. This option is ignored if
.Fl f
has been specified.
.It Fl s Ar size
Specify the number of payload bytes to be sent. The default is 64. The
maximum size is 65531. Use this option with caution. Some implementations
may not like large sizes and may hang or even crash.
.El
.Sh BUGS
Could collect more statistic. Could check for duplicated, corrupted
and lost packets.
.Sh DIAGNOSTICS
.Ex -std
.Sh SEE ALSO
.Xr netgraph 3 ,
.Xr netgraph 4 ,
.Xr ng_l2cap 4 ,
.Xr l2control 8
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View File

@ -0,0 +1,279 @@
/*
* l2ping.c
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: l2ping.c,v 1.9 2002/09/04 21:28:05 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <assert.h>
#include <bitstring.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ng_hci.h>
#include <ng_l2cap.h>
#include <ng_btsocket.h>
static void usage (void);
static void tv_sub (struct timeval *, struct timeval const *);
static double tv2msec (struct timeval const *);
#undef min
#define min(x, y) (((x) > (y))? (y) : (x))
static char const pattern[] = "1234567890-";
#define PATTERN_SIZE (sizeof(pattern) - 1)
/*
* Main
*/
int
main(int argc, char *argv[])
{
struct ng_btsocket_l2cap_raw_ping r;
int n, s, count, wait, flood, fail;
struct timeval a, b;
/* Set defaults */
memset(&r, 0, sizeof(r));
r.echo_data = calloc(NG_L2CAP_MAX_ECHO_SIZE, sizeof(u_int8_t));
if (r.echo_data == NULL) {
fprintf(stderr, "Failed to allocate echo data buffer");
exit(1);
}
r.echo_size = 64; /* bytes */
count = -1; /* unlimited */
wait = 1; /* sec */
flood = 0;
/* Parse command line arguments */
while ((n = getopt(argc, argv, "a:c:fi:n:s:S:")) != -1) {
switch (n) {
case 'a':
case 'S': {
int a0, a1, a2, a3, a4, a5;
if (sscanf(optarg, "%x:%x:%x:%x:%x:%x",
&a5, &a4, &a3, &a2, &a1, &a0) != 6)
usage();
if (n == 'a') {
/* destination bdaddr */
r.echo_dst.b[0] = (a0 & 0xff);
r.echo_dst.b[1] = (a1 & 0xff);
r.echo_dst.b[2] = (a2 & 0xff);
r.echo_dst.b[3] = (a3 & 0xff);
r.echo_dst.b[4] = (a4 & 0xff);
r.echo_dst.b[5] = (a5 & 0xff);
} else {
/* source bdaddr */
r.echo_src.b[0] = (a0 & 0xff);
r.echo_src.b[1] = (a1 & 0xff);
r.echo_src.b[2] = (a2 & 0xff);
r.echo_src.b[3] = (a3 & 0xff);
r.echo_src.b[4] = (a4 & 0xff);
r.echo_src.b[5] = (a5 & 0xff);
}
} break;
case 'c':
count = atoi(optarg);
if (count <= 0)
usage();
break;
case 'f':
flood = 1;
break;
case 'i':
wait = atoi(optarg);
if (wait <= 0)
usage();
break;
case 's':
r.echo_size = atoi(optarg);
if ((int) r.echo_size < sizeof(int))
usage();
if (r.echo_size > NG_L2CAP_MAX_ECHO_SIZE)
r.echo_size = NG_L2CAP_MAX_ECHO_SIZE;
break;
default:
usage();
break;
}
}
if (memcmp(&r.echo_dst, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
usage();
s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP);
if (s < 0)
err(2, "Could not create socket");
if (memcmp(&r.echo_src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) != 0) {
struct sockaddr_l2cap sa;
memset(&sa, 0, sizeof(sa));
sa.l2cap_len = sizeof(sa);
sa.l2cap_family = AF_BLUETOOTH;
memcpy(&sa.l2cap_bdaddr, &r.echo_src, sizeof(bdaddr_t));
if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
err(3,
"Could not bind socket, src bdaddr=%x:%x:%x:%x:%x:%x",
sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
err(4,
"Could not connect socket, src bdaddr=%x:%x:%x:%x:%x:%x",
sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4],
sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2],
sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]);
}
/* Fill pattern */
for (n = 0; n < r.echo_size; ) {
int avail = min(r.echo_size - n, PATTERN_SIZE);
memcpy(r.echo_data + n, pattern, avail);
n += avail;
}
/* Start ping'ing */
for (n = 0; count == -1 || count > 0; n ++) {
if (gettimeofday(&a, NULL) < 0)
err(5, "Could not gettimeofday(a)");
fail = 0;
*((int *)(r.echo_data)) = htonl(n);
if (ioctl(s, SIOC_L2CAP_L2CA_PING, &r, sizeof(r)) < 0) {
r.result = errno;
fail = 1;
/*
warn("Could not ping, dst bdaddr=%x:%x:%x:%x:%x:%x",
r.echo_dst.b[5], r.echo_dst.b[4],
r.echo_dst.b[3], r.echo_dst.b[2],
r.echo_dst.b[1], r.echo_dst.b[0]);
*/
}
if (gettimeofday(&b, NULL) < 0)
err(7, "Could not gettimeofday(b)");
tv_sub(&b, &a);
fprintf(stdout,
"%d bytes from %x:%x:%x:%x:%x:%x seq_no=%d time=%.3f ms result=%#x %s\n",
r.echo_size,
r.echo_dst.b[5], r.echo_dst.b[4],
r.echo_dst.b[3], r.echo_dst.b[2],
r.echo_dst.b[1], r.echo_dst.b[0],
ntohl(*((int *)(r.echo_data))),
tv2msec(&b), r.result,
((fail == 0)? "" : strerror(errno)));
if (!flood) {
/* Wait */
a.tv_sec = wait;
a.tv_usec = 0;
select(0, NULL, NULL, NULL, &a);
}
if (count != -1)
count --;
}
free(r.echo_data);
close(s);
return (0);
} /* main */
/*
* a -= b, for timevals
*/
static void
tv_sub(struct timeval *a, struct timeval const *b)
{
if (a->tv_usec < b->tv_usec) {
a->tv_usec += 1000000;
a->tv_sec -= 1;
}
a->tv_usec -= b->tv_usec;
a->tv_sec -= b->tv_sec;
} /* tv_sub */
/*
* convert tv to msec
*/
static double
tv2msec(struct timeval const *tvp)
{
return(((double)tvp->tv_usec)/1000.0 + ((double)tvp->tv_sec)*1000.0);
} /* tv2msec */
/*
* Usage
*/
static void
usage(void)
{
fprintf(stderr, "Usage: l2ping -a bd_addr " \
"[-S bd_addr -c count -i wait -s size]\n");
fprintf(stderr, "Where:\n");
fprintf(stderr, "\t-S bd_addr - Source BD_ADDR\n");
fprintf(stderr, "\t-a bd_addr - Remote BD_ADDR to ping\n");
fprintf(stderr, "\t-c count - Number of packets to send\n");
fprintf(stderr, "\t-f - No delay (soft of flood)\n");
fprintf(stderr, "\t-i wait - Delay between packets (sec)\n");
fprintf(stderr, "\t-s size - Packet size (bytes), " \
"between %d and %d\n", sizeof(int), NG_L2CAP_MAX_ECHO_SIZE);
exit(255);
} /* usage */