Commit 6c3b738c authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 9700fe23 6cab0e06
......@@ -12,11 +12,20 @@ CONFIG_BLUEZ_HCIUART
HCI UART (H4) protocol support
CONFIG_BLUEZ_HCIUART_H4
UART (H4) is serial protocol for communication between Bluetooth
device and host. This protocol is required for most UART based
Bluetooth device (including PCMCIA and CF).
device and host. This protocol is required for most Bluetooth devices
with UART interface, including PCMCIA and CF cards.
Say Y here to compile support for HCI UART (H4) protocol.
HCI BCSP protocol support
CONFIG_BLUEZ_HCIUART_BCSP
BCSP (BlueCore Serial Protocol) is serial protocol for communication
between Bluetooth device and host. This protocol is required for non
USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and
CF cards.
Say Y here to compile support for HCI BCSP protocol.
HCI USB driver
CONFIG_BLUEZ_HCIUSB
Bluetooth HCI USB driver.
......@@ -26,15 +35,6 @@ CONFIG_BLUEZ_HCIUSB
Say Y here to compile support for Bluetooth USB devices into the
kernel or say M to compile it as module (hci_usb.o).
HCI USB firmware download support
CONFIG_BLUEZ_USB_FW_LOAD
Firmware download support for Bluetooth USB devices.
This support is required for devices like Broadcom BCM2033.
HCI USB driver uses external firmware downloader program provided
in BlueFW package.
For more information, see <http://bluez.sf.net/>.
HCI USB zero packet support
CONFIG_BLUEZ_USB_ZERO_PACKET
Support for USB zero packets.
......
......@@ -3,13 +3,13 @@ comment 'Bluetooth device drivers'
dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
bool ' Firmware download support' CONFIG_BLUEZ_USB_FW_LOAD
bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET
fi
dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
bool ' BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
fi
dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
......
......@@ -11,6 +11,7 @@ obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o
hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o
hci_uart-objs := $(hci_uart-y)
include $(TOPDIR)/Rules.make
This diff is collapsed.
/*
BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
Based on
hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com>
ABCSP by Carl Orsborn <cjo@csr.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
/*
* $Id: hci_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $
*/
#ifndef __HCI_BCSP_H__
#define __HCI_BCSP_H__
#define BCSP_TXWINSIZE 4
#define BCSP_ACK_PKT 0x05
#define BCSP_LE_PKT 0x06
struct bcsp_struct {
struct sk_buff_head unack; /* Unack'ed packets queue */
struct sk_buff_head rel; /* Reliable packets queue */
struct sk_buff_head unrel; /* Unreliable packets queue */
unsigned long rx_count;
struct sk_buff *rx_skb;
u8 rxseq_txack; /* rxseq == txack. */
u8 rxack; /* Last packet sent by us that the peer ack'ed */
struct timer_list tbcsp;
enum {
BCSP_W4_PKT_DELIMITER,
BCSP_W4_PKT_START,
BCSP_W4_BCSP_HDR,
BCSP_W4_DATA,
BCSP_W4_CRC
} rx_state;
enum {
BCSP_ESCSTATE_NOESC,
BCSP_ESCSTATE_ESC
} rx_esc_state;
u16 message_crc;
u8 txack_req; /* Do we need to send ack's to the peer? */
/* Reliable packet sequence number - used to assign seq to each rel pkt. */
u8 msgq_txseq;
};
#endif /* __HCI_BCSP_H__ */
......@@ -25,9 +25,9 @@
/*
* BlueZ HCI UART(H4) protocol.
*
* $Id: hci_h4.c,v 1.2 2002/04/17 17:37:20 maxk Exp $
* $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $
*/
#define VERSION "1.1"
#define VERSION "1.2"
#include <linux/config.h>
#include <linux/module.h>
......@@ -64,63 +64,61 @@
#endif
/* Initialize protocol */
static int h4_open(struct n_hci *n_hci)
static int h4_open(struct hci_uart *hu)
{
struct h4_struct *h4;
BT_DBG("n_hci %p", n_hci);
BT_DBG("hu %p", hu);
h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
if (!h4)
return -ENOMEM;
memset(h4, 0, sizeof(*h4));
n_hci->priv = h4;
skb_queue_head_init(&h4->txq);
hu->priv = h4;
return 0;
}
/* Flush protocol data */
static int h4_flush(struct n_hci *n_hci)
static int h4_flush(struct hci_uart *hu)
{
BT_DBG("n_hci %p", n_hci);
struct h4_struct *h4 = hu->priv;
BT_DBG("hu %p", hu);
skb_queue_purge(&h4->txq);
return 0;
}
/* Close protocol */
static int h4_close(struct n_hci *n_hci)
static int h4_close(struct hci_uart *hu)
{
struct h4_struct *h4 = n_hci->priv;
n_hci->priv = NULL;
struct h4_struct *h4 = hu->priv;
hu->priv = NULL;
BT_DBG("n_hci %p", n_hci);
BT_DBG("hu %p", hu);
skb_queue_purge(&h4->txq);
if (h4->rx_skb)
kfree_skb(h4->rx_skb);
hu->priv = NULL;
kfree(h4);
return 0;
}
/* Send data */
static int h4_send(struct n_hci *n_hci, void *data, int len)
/* Enqueue frame for transmittion (padding, crc, etc) */
static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{
struct tty_struct *tty = n_hci->tty;
BT_DBG("n_hci %p len %d", n_hci, len);
struct h4_struct *h4 = hu->priv;
/* Send frame to TTY driver */
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
return tty->driver.write(tty, 0, data, len);
}
/* Init frame before queueing (padding, crc, etc) */
static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb)
{
BT_DBG("n_hci %p skb %p", n_hci, skb);
BT_DBG("hu %p skb %p", hu, skb);
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
return skb;
skb_queue_tail(&h4->txq, skb);
return 0;
}
static inline int h4_check_data_len(struct h4_struct *h4, int len)
......@@ -132,7 +130,7 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
hci_recv_frame(h4->rx_skb);
} else if (len > room) {
BT_ERR("Data length is to large");
BT_ERR("Data length is too large");
kfree_skb(h4->rx_skb);
} else {
h4->rx_state = H4_W4_DATA;
......@@ -147,16 +145,17 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
}
/* Recv data */
static int h4_recv(struct n_hci *n_hci, void *data, int count)
static int h4_recv(struct hci_uart *hu, void *data, int count)
{
struct h4_struct *h4 = n_hci->priv;
struct h4_struct *h4 = hu->priv;
register char *ptr;
hci_event_hdr *eh;
hci_acl_hdr *ah;
hci_sco_hdr *sh;
register int len, type, dlen;
BT_DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count);
BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
hu, count, h4->rx_state, h4->rx_count);
ptr = data;
while (count) {
......@@ -204,7 +203,7 @@ static int h4_recv(struct n_hci *n_hci, void *data, int count)
h4_check_data_len(h4, sh->dlen);
continue;
};
}
}
/* H4_W4_PACKET_TYPE */
......@@ -232,7 +231,7 @@ static int h4_recv(struct n_hci *n_hci, void *data, int count)
default:
BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
n_hci->hdev.stat.err_rx++;
hu->hdev.stat.err_rx++;
ptr++; count--;
continue;
};
......@@ -246,19 +245,25 @@ static int h4_recv(struct n_hci *n_hci, void *data, int count)
h4->rx_count = 0;
return 0;
}
h4->rx_skb->dev = (void *) &n_hci->hdev;
h4->rx_skb->dev = (void *) &hu->hdev;
h4->rx_skb->pkt_type = type;
}
return count;
}
static struct sk_buff *h4_dequeue(struct hci_uart *hu)
{
struct h4_struct *h4 = hu->priv;
return skb_dequeue(&h4->txq);
}
static struct hci_uart_proto h4p = {
.id = HCI_UART_H4,
.open = h4_open,
.close = h4_close,
.send = h4_send,
.recv = h4_recv,
.preq = h4_preq,
.enqueue = h4_enqueue,
.dequeue = h4_dequeue,
.flush = h4_flush,
};
......
......@@ -23,7 +23,7 @@
*/
/*
* $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
* $Id: hci_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
*/
#ifdef __KERNEL__
......@@ -31,6 +31,7 @@ struct h4_struct {
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
struct sk_buff_head txq;
};
/* H4 receiver States */
......
This diff is collapsed.
......@@ -23,7 +23,7 @@
*/
/*
* $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
* $Id: hci_uart.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
*/
#ifndef N_HCI
......@@ -42,19 +42,19 @@
#define HCI_UART_NCSP 2
#ifdef __KERNEL__
struct n_hci;
struct hci_uart;
struct hci_uart_proto {
unsigned int id;
int (*open)(struct n_hci *n_hci);
int (*recv)(struct n_hci *n_hci, void *data, int len);
int (*send)(struct n_hci *n_hci, void *data, int len);
int (*close)(struct n_hci *n_hci);
int (*flush)(struct n_hci *n_hci);
struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb);
int (*open)(struct hci_uart *hu);
int (*close)(struct hci_uart *hu);
int (*flush)(struct hci_uart *hu);
int (*recv)(struct hci_uart *hu, void *data, int len);
int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
struct sk_buff *(*dequeue)(struct hci_uart *hu);
};
struct n_hci {
struct hci_uart {
struct tty_struct *tty;
struct hci_dev hdev;
unsigned long flags;
......@@ -62,19 +62,20 @@ struct n_hci {
struct hci_uart_proto *proto;
void *priv;
struct sk_buff_head txq;
struct sk_buff *tx_skb;
unsigned long tx_state;
spinlock_t rx_lock;
};
/* N_HCI flag bits */
#define N_HCI_PROTO_SET 0x00
/* HCI_UART flag bits */
#define HCI_UART_PROTO_SET 0x00
/* TX states */
#define N_HCI_SENDING 1
#define N_HCI_TX_WAKEUP 2
#define HCI_UART_SENDING 1
#define HCI_UART_TX_WAKEUP 2
int hci_uart_register_proto(struct hci_uart_proto *p);
int hci_uart_unregister_proto(struct hci_uart_proto *p);
int hci_uart_tx_wakeup(struct hci_uart *hu);
#endif /* __KERNEL__ */
......@@ -28,9 +28,9 @@
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
*
* $Id: hci_usb.c,v 1.6 2002/04/17 17:37:20 maxk Exp $
* $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $
*/
#define VERSION "2.0"
#define VERSION "2.1"
#include <linux/config.h>
#include <linux/module.h>
......@@ -73,7 +73,7 @@
static struct usb_driver hci_usb_driver;
static struct usb_device_id usb_bluetooth_ids [] = {
static struct usb_device_id bluetooth_ids[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
......@@ -83,7 +83,14 @@ static struct usb_device_id usb_bluetooth_ids [] = {
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
MODULE_DEVICE_TABLE (usb, bluetooth_ids);
static struct usb_device_id ignore_ids[] = {
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE(0x0a5c, 0x2033) },
{ } /* Terminating entry */
};
static void hci_usb_interrupt(struct urb *urb);
static void hci_usb_rx_complete(struct urb *urb);
......@@ -193,21 +200,25 @@ static int hci_usb_open(struct hci_dev *hdev)
{
struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
int i, err;
long flags;
unsigned long flags;
BT_DBG("%s", hdev->name);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
MOD_INC_USE_COUNT;
write_lock_irqsave(&husb->completion_lock, flags);
err = hci_usb_enable_intr(husb);
if (!err) {
for (i = 0; i < HCI_MAX_BULK_TX; i++)
for (i = 0; i < HCI_MAX_BULK_RX; i++)
hci_usb_rx_submit(husb, NULL);
} else
} else {
clear_bit(HCI_RUNNING, &hdev->flags);
MOD_DEC_USE_COUNT;
}
write_unlock_irqrestore(&husb->completion_lock, flags);
return err;
......@@ -246,7 +257,7 @@ static inline void hci_usb_unlink_urbs(struct hci_usb *husb)
static int hci_usb_close(struct hci_dev *hdev)
{
struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
long flags;
unsigned long flags;
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
......@@ -260,6 +271,8 @@ static int hci_usb_close(struct hci_dev *hdev)
hci_usb_flush(hdev);
write_unlock_irqrestore(&husb->completion_lock, flags);
MOD_DEC_USE_COUNT;
return 0;
}
......@@ -587,76 +600,9 @@ static void hci_usb_destruct(struct hci_dev *hdev)
husb = (struct hci_usb *) hdev->driver_data;
kfree(husb);
MOD_DEC_USE_COUNT;
}
#ifdef CONFIG_BLUEZ_USB_FW_LOAD
/* Support for user mode Bluetooth USB firmware loader */
#define FW_LOADER "/sbin/bluefw"
static int errno;
static int hci_usb_fw_exec(void *dev)
{
char *envp[] = { "HOME=/", "TERM=linux",
"PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
char *argv[] = { FW_LOADER, dev, NULL };
int err;
err = exec_usermodehelper(FW_LOADER, argv, envp);
if (err)
BT_ERR("failed to exec %s %s", FW_LOADER, (char *)dev);
return err;
}
static int hci_usb_fw_load(struct usb_device *udev)
{
sigset_t tmpsig;
char dev[16];
pid_t pid;
int result;
/* Check if root fs is mounted */
if (!current->fs->root) {
BT_ERR("root fs not mounted");
return -EPERM;
}
sprintf(dev, "%3.3d/%3.3d", udev->bus->busnum, udev->devnum);
pid = kernel_thread(hci_usb_fw_exec, (void *)dev, 0);
if (pid < 0) {
BT_ERR("fork failed, errno %d\n", -pid);
return pid;
}
/* Block signals, everything but SIGKILL/SIGSTOP */
spin_lock_irq(&current->sig->siglock);
tmpsig = current->blocked;
siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
recalc_sigpending();
spin_unlock_irq(&current->sig->siglock);
result = waitpid(pid, NULL, __WCLONE);
/* Allow signals again */
spin_lock_irq(&current->sig->siglock);
current->blocked = tmpsig;
recalc_sigpending();
spin_unlock_irq(&current->sig->siglock);
if (result != pid) {
BT_ERR("waitpid failed pid %d errno %d\n", pid, -result);
return -result;
}
return 0;
}
#endif /* CONFIG_BLUEZ_USB_FW_LOAD */
static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];
......@@ -673,15 +619,13 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
BT_DBG("intf %p", intf);
/* Check our black list */
if (usb_match_id(intf, ignore_ids))
return -EIO;
/* Check number of endpoints */
if (intf->altsetting[0].bNumEndpoints < 3)
return -ENODEV;
MOD_INC_USE_COUNT;
#ifdef CONFIG_BLUEZ_USB_FW_LOAD
hci_usb_fw_load(udev);
#endif
return -EIO;
memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
......@@ -802,7 +746,6 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
kfree(husb);
done:
MOD_DEC_USE_COUNT;
return -EIO;
}
......@@ -811,9 +754,9 @@ static void hci_usb_disconnect(struct usb_interface *intf)
struct hci_usb *husb = dev_get_drvdata(&intf->dev);
struct hci_dev *hdev;
dev_set_drvdata(&intf->dev, NULL);
if (!husb)
return;
dev_set_drvdata(&intf->dev, NULL);
hdev = &husb->hdev;
BT_DBG("%s", hdev->name);
......@@ -831,7 +774,7 @@ static struct usb_driver hci_usb_driver = {
.name = "hci_usb",
.probe = hci_usb_probe,
.disconnect = hci_usb_disconnect,
.id_table = usb_bluetooth_ids,
.id_table = bluetooth_ids
};
int hci_usb_init(void)
......
......@@ -55,8 +55,8 @@ struct hci_usb {
__u8 intr_ep;
__u8 intr_interval;
struct urb * intr_urb;
struct sk_buff * intr_skb;
struct urb *intr_urb;
struct sk_buff *intr_skb;
rwlock_t completion_lock;
......
......@@ -50,6 +50,7 @@
#define BTPROTO_HCI 1
#define BTPROTO_SCO 2
#define BTPROTO_RFCOMM 3
#define BTPROTO_BNEP 4
#define SOL_HCI 0
#define SOL_L2CAP 6
......@@ -199,14 +200,4 @@ int hci_sock_cleanup(void);
int bterr(__u16 code);
#ifndef MODULE_LICENSE
#define MODULE_LICENSE(x)
#endif
#ifndef list_for_each_safe
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#endif
#endif /* __BLUETOOTH_H */
......@@ -113,10 +113,10 @@ enum {
#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK)
/* ACL flags */
#define ACL_CONT 0x0001
#define ACL_START 0x0002
#define ACL_ACTIVE_BCAST 0x0010
#define ACL_PICO_BCAST 0x0020
#define ACL_CONT 0x01
#define ACL_START 0x02
#define ACL_ACTIVE_BCAST 0x04
#define ACL_PICO_BCAST 0x08
/* Baseband links */
#define SCO_LINK 0x00
......@@ -542,7 +542,7 @@ typedef struct {
bdaddr_t bdaddr;
__u8 role;
} __attribute__ ((packed)) evt_role_change;
#define EVT_ROLE_CHANGE_SIZE 1
#define EVT_ROLE_CHANGE_SIZE 8
#define EVT_PIN_CODE_REQ 0x16
typedef struct {
......@@ -658,6 +658,12 @@ struct sockaddr_hci {
#define HCI_DEV_NONE 0xffff
struct hci_filter {
unsigned long type_mask;
unsigned long event_mask[2];
__u16 opcode;
};
struct hci_ufilter {
__u32 type_mask;
__u32 event_mask[2];
__u16 opcode;
......@@ -668,20 +674,6 @@ struct hci_filter {
#define HCI_FLT_OGF_BITS 63
#define HCI_FLT_OCF_BITS 127
#if BITS_PER_LONG == 64
static inline void hci_set_bit(int nr, void *addr)
{
*((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31));
}
static inline int hci_test_bit(int nr, void *addr)
{
return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
}
#else
#define hci_set_bit set_bit
#define hci_test_bit test_bit
#endif
/* Ioctl requests structures */
struct hci_dev_stats {
__u32 err_rx;
......
......@@ -149,7 +149,7 @@ struct hci_conn {
extern struct hci_proto *hci_proto[];
extern struct list_head hdev_list;
extern spinlock_t hdev_list_lock;
extern rwlock_t hdev_list_lock;
/* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds
......@@ -339,8 +339,8 @@ static inline void hci_sched_tx(struct hci_dev *hdev)
/* ----- HCI protocols ----- */
struct hci_proto {
char *name;
__u32 id;
__u32 flags;
unsigned int id;
unsigned long flags;
void *priv;
......@@ -450,12 +450,11 @@ struct hci_pinfo {
#define HCI_SFLT_MAX_OGF 4
struct hci_sec_filter {
__u32 type_mask;
__u32 event_mask[2];
__u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
unsigned long type_mask;
unsigned long event_mask[2];
unsigned long ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
};
/* ----- HCI requests ----- */
#define HCI_REQ_DONE 0
#define HCI_REQ_PEND 1
......
/*
RFCOMM implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
/*
RPN support - Dirk Husemann <hud@zurich.ibm.com>
*/
/*
* $Id: rfcomm.h,v 1.29 2002/10/02 20:26:17 maxk Exp $
*/
#ifndef __RFCOMM_H
#define __RFCOMM_H
#define RFCOMM_PSM 3
#define RFCOMM_CONN_TIMEOUT (HZ * 30)
#define RFCOMM_DISC_TIMEOUT (HZ * 20)
#define RFCOMM_DEFAULT_MTU 127
#define RFCOMM_DEFAULT_CREDITS 7
#define RFCOMM_MAX_L2CAP_MTU 1024
#define RFCOMM_MAX_CREDITS 40
#define RFCOMM_SKB_HEAD_RESERVE 8
#define RFCOMM_SKB_TAIL_RESERVE 2
#define RFCOMM_SKB_RESERVE (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE)
#define RFCOMM_SABM 0x2f
#define RFCOMM_DISC 0x43
#define RFCOMM_UA 0x63
#define RFCOMM_DM 0x0f
#define RFCOMM_UIH 0xef
#define RFCOMM_TEST 0x08
#define RFCOMM_FCON 0x28
#define RFCOMM_FCOFF 0x18
#define RFCOMM_MSC 0x38
#define RFCOMM_RPN 0x24
#define RFCOMM_RLS 0x14
#define RFCOMM_PN 0x20
#define RFCOMM_NSC 0x04
#define RFCOMM_V24_FC 0x02
#define RFCOMM_V24_RTC 0x04
#define RFCOMM_V24_RTR 0x08
#define RFCOMM_V24_IC 0x40
#define RFCOMM_V24_DV 0x80
#define RFCOMM_RPN_BR_2400 0x0
#define RFCOMM_RPN_BR_4800 0x1
#define RFCOMM_RPN_BR_7200 0x2
#define RFCOMM_RPN_BR_9600 0x3
#define RFCOMM_RPN_BR_19200 0x4
#define RFCOMM_RPN_BR_38400 0x5
#define RFCOMM_RPN_BR_57600 0x6
#define RFCOMM_RPN_BR_115200 0x7
#define RFCOMM_RPN_BR_230400 0x8
#define RFCOMM_RPN_DATA_5 0x0
#define RFCOMM_RPN_DATA_6 0x1
#define RFCOMM_RPN_DATA_7 0x2
#define RFCOMM_RPN_DATA_8 0x3
#define RFCOMM_RPN_STOP_1 0
#define RFCOMM_RPN_STOP_15 1
#define RFCOMM_RPN_PARITY_NONE 0x0
#define RFCOMM_RPN_PARITY_ODD 0x4
#define RFCOMM_RPN_PARITY_EVEN 0x5
#define RFCOMM_RPN_PARITY_MARK 0x6
#define RFCOMM_RPN_PARITY_SPACE 0x7
#define RFCOMM_RPN_FLOW_NONE 0x00
#define RFCOMM_RPN_XON_CHAR 0x11
#define RFCOMM_RPN_XOFF_CHAR 0x13
#define RFCOMM_RPN_PM_BITRATE 0x0001
#define RFCOMM_RPN_PM_DATA 0x0002
#define RFCOMM_RPN_PM_STOP 0x0004
#define RFCOMM_RPN_PM_PARITY 0x0008
#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010
#define RFCOMM_RPN_PM_XON 0x0020
#define RFCOMM_RPN_PM_XOFF 0x0040
#define RFCOMM_RPN_PM_FLOW 0x3F00
#define RFCOMM_RPN_PM_ALL 0x3F7F
struct rfcomm_hdr {
u8 addr;
u8 ctrl;
u8 len; // Actual size can be 2 bytes
} __attribute__ ((packed));
struct rfcomm_cmd {
u8 addr;
u8 ctrl;
u8 len;
u8 fcs;
} __attribute__ ((packed));
struct rfcomm_mcc {
u8 type;
u8 len;
} __attribute__ ((packed));
struct rfcomm_pn {
u8 dlci;
u8 flow_ctrl;
u8 priority;
u8 ack_timer;
u16 mtu;
u8 max_retrans;
u8 credits;
} __attribute__ ((packed));
struct rfcomm_rpn {
u8 dlci;
u8 bit_rate;
u8 line_settings;
u8 flow_ctrl;
u8 xon_char;
u8 xoff_char;
u16 param_mask;
} __attribute__ ((packed));
struct rfcomm_msc {
u8 dlci;
u8 v24_sig;
} __attribute__ ((packed));
/* ---- Core structures, flags etc ---- */
struct rfcomm_session {
struct list_head list;
struct socket *sock;
unsigned long state;
unsigned long flags;
atomic_t refcnt;
int initiator;
/* Default DLC parameters */
uint mtu;
uint credits;
struct list_head dlcs;
};
struct rfcomm_dlc {
struct list_head list;
struct rfcomm_session *session;
struct sk_buff_head tx_queue;
struct timer_list timer;
spinlock_t lock;
unsigned long state;
unsigned long flags;
atomic_t refcnt;
u8 dlci;
u8 addr;
uint mtu;
u8 v24_sig;
uint credits;
uint rx_credits;
uint tx_credits;
void *owner;
void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
void (*state_change)(struct rfcomm_dlc *d, int err);
void (*modem_status)(struct rfcomm_dlc *d, int v24_sig);
};
/* DLC and session flags */
#define RFCOMM_RX_THROTTLED 0
#define RFCOMM_TX_THROTTLED 1
#define RFCOMM_MSC_PENDING 2
#define RFCOMM_TIMED_OUT 3
/* Scheduling flags and events */
#define RFCOMM_SCHED_STATE 0
#define RFCOMM_SCHED_RX 1
#define RFCOMM_SCHED_TX 2
#define RFCOMM_SCHED_TIMEO 3
#define RFCOMM_SCHED_WAKEUP 31
extern struct task_struct *rfcomm_thread;
extern unsigned long rfcomm_event;
static inline void rfcomm_schedule(uint event)
{
if (!rfcomm_thread)
return;
//set_bit(event, &rfcomm_event);
if (!test_and_set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event))
wake_up_process(rfcomm_thread);
}
extern struct semaphore rfcomm_sem;
#define rfcomm_lock() down(&rfcomm_sem);
#define rfcomm_unlock() up(&rfcomm_sem);
/* ---- RFCOMM DLCs (channels) ---- */
struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
void rfcomm_dlc_free(struct rfcomm_dlc *d);
int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
int rfcomm_dlc_modem_status(struct rfcomm_dlc *d, int v24_sig);
#define rfcomm_dlc_lock(d) spin_lock(&d->lock)
#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock)
static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
{
atomic_inc(&d->refcnt);
}
static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
{
if (atomic_dec_and_test(&d->refcnt))
rfcomm_dlc_free(d);
}
extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
{
if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags))
__rfcomm_dlc_throttle(d);
}
static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
{
if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags))
__rfcomm_dlc_unthrottle(d);
}
/* ---- RFCOMM sessions ---- */
struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
void rfcomm_session_del(struct rfcomm_session *s);
void rfcomm_session_close(struct rfcomm_session *s, int err);
static inline void rfcomm_session_hold(struct rfcomm_session *s)
{
atomic_inc(&s->refcnt);
}
static inline void rfcomm_session_put(struct rfcomm_session *s)
{
if (atomic_dec_and_test(&s->refcnt))
rfcomm_session_del(s);
}
/* ---- RFCOMM chechsum ---- */
extern u8 rfcomm_crc_table[];
/* ---- RFCOMM sockets ---- */
struct sockaddr_rc {
sa_family_t rc_family;
bdaddr_t rc_bdaddr;
u8 rc_channel;
};
#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) &sk->protinfo)
struct rfcomm_pinfo {
struct rfcomm_dlc *dlc;
u8 channel;
};
int rfcomm_init_sockets(void);
void rfcomm_cleanup_sockets(void);
int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
/* ---- RFCOMM TTY ---- */
#define RFCOMM_MAX_DEV 256
#define RFCOMMCREATEDEV _IOW('R', 200, int)
#define RFCOMMRELEASEDEV _IOW('R', 201, int)
#define RFCOMMGETDEVLIST _IOR('R', 210, int)
#define RFCOMMGETDEVINFO _IOR('R', 211, int)
#define RFCOMMSTEALDLC _IOW('R', 220, int)
#define RFCOMM_REUSE_DLC 0
#define RFCOMM_RELEASE_ONHUP 1
#define RFCOMM_HANGUP_NOW 2
#define RFCOMM_TTY_ATTACHED 3
struct rfcomm_dev_req {
s16 dev_id;
u32 flags;
bdaddr_t src;
bdaddr_t dst;
u8 channel;
};
struct rfcomm_dev_info {
s16 id;
u32 flags;
u16 state;
bdaddr_t src;
bdaddr_t dst;
u8 channel;
};
struct rfcomm_dev_list_req {
u16 dev_num;
struct rfcomm_dev_info dev_info[0];
};
int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
int rfcomm_init_ttys(void);
void rfcomm_cleanup_ttys(void);
#endif /* __RFCOMM_H */
......@@ -10,7 +10,9 @@ CONFIG_BLUEZ
BlueZ Core (HCI device and connection manager, scheduler)
HCI Device drivers (interface to the hardware)
L2CAP Module (L2CAP protocol)
RFCOMM Module (RFCOMM protocol)
SCO Module (SCO links)
BNEP Module (BNEP protocol)
Say Y here to enable Linux Bluetooth support and to build BlueZ Core
layer.
......@@ -31,6 +33,19 @@ CONFIG_BLUEZ_L2CAP
Say Y here to compile L2CAP support into the kernel or say M to
compile it as module (l2cap.o).
RFCOMM protocol support
CONFIG_BLUEZ_RFCOMM
RFCOMM provides connection oriented stream transport. RFCOMM
support is required for Dialup Networking, OBEX and other Bluetooth
applications.
Say Y here to compile RFCOMM support into the kernel or say M to
compile it as module (rfcomm.o).
RFCOMM TTY emulation support
CONFIG_RFCOMM_TTY
This options enables TTY emulation support for RFCOMM channels.
SCO links support
CONFIG_BLUEZ_SCO
SCO link provides voice transport over Bluetooth. SCO support is
......@@ -39,3 +54,16 @@ CONFIG_BLUEZ_SCO
Say Y here to compile SCO support into the kernel or say M to
compile it as module (sco.o).
BNEP protocol support
CONFIG_BLUEZ_BNEP
BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
emulation layer on top of Bluetooth. BNEP is required for Bluetooth
PAN (Personal Area Network).
To use BNEP, you will need user-space utilities provided in the
BlueZ-PAN package.
For more information, see <http://bluez.sourceforge.net>.
Say Y here to compile BNEP support into the kernel or say M to
compile it as module (bnep.o).
......@@ -10,6 +10,8 @@ if [ "$CONFIG_NET" != "n" ]; then
if [ "$CONFIG_BLUEZ" != "n" ]; then
dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
source net/bluetooth/rfcomm/Config.in
source net/bluetooth/bnep/Config.in
source drivers/bluetooth/Config.in
fi
endmenu
......
......@@ -8,6 +8,18 @@ obj-$(CONFIG_BLUEZ) += bluez.o
obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
obj-$(CONFIG_BLUEZ_SCO) += sco.o
subdir-$(CONFIG_BLUEZ_BNEP) += bnep
ifeq ($(CONFIG_BLUEZ_BNEP),y)
obj-y += bnep/bnep.o
endif
subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
obj-y += rfcomm/rfcomm.o
endif
bluez-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
include $(TOPDIR)/Rules.make
......@@ -27,7 +27,7 @@
*
* $Id: af_bluetooth.c,v 1.3 2002/04/17 17:37:15 maxk Exp $
*/
#define VERSION "2.0"
#define VERSION "2.2"
#include <linux/config.h>
#include <linux/module.h>
......@@ -57,7 +57,7 @@
#endif
/* Bluetooth sockets */
#define BLUEZ_MAX_PROTO 4
#define BLUEZ_MAX_PROTO 5
static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
static kmem_cache_t *bluez_sock_cache;
......@@ -136,18 +136,18 @@ struct sock *bluez_sock_alloc(struct socket *sock, int proto, int pi_size, int p
void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
{
write_lock(&l->lock);
write_lock_bh(&l->lock);
sk->next = l->head;
l->head = sk;
sock_hold(sk);
write_unlock(&l->lock);
write_unlock_bh(&l->lock);
}
void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
{
struct sock **skp;
write_lock(&l->lock);
write_lock_bh(&l->lock);
for (skp = &l->head; *skp; skp = &((*skp)->next)) {
if (*skp == sk) {
*skp = sk->next;
......@@ -155,7 +155,7 @@ void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
break;
}
}
write_unlock(&l->lock);
write_unlock_bh(&l->lock);
}
void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
......@@ -265,6 +265,9 @@ unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table
if (sk->state == BT_CLOSED)
mask |= POLLHUP;
if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2)
return mask;
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
......
dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
bool ' Multicast filter support' CONFIG_BNEP_MC_FILTER
bool ' Protocol filter support' CONFIG_BNEP_PROTO_FILTER
fi
#
# Makefile for BNEP protocol
#
O_TARGET := bnep.o
obj-y := core.o sock.o netdev.o crc32.o
obj-m += $(O_TARGET)
include $(TOPDIR)/Rules.make
/*
BNEP protocol definition for Linux Bluetooth stack (BlueZ).
Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* $Id: bnep.h,v 1.5 2002/08/04 21:23:58 maxk Exp $
*/
#ifndef _BNEP_H
#define _BNEP_H
#include <linux/types.h>
#include <net/bluetooth/bluetooth.h>
#include "crc32.h"
// Limits
#define BNEP_MAX_PROTO_FILTERS 5
#define BNEP_MAX_MULTICAST_FILTERS 20
// UUIDs
#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
#define BNEP_UUID16 0x02
#define BNEP_UUID32 0x04
#define BNEP_UUID128 0x16
#define BNEP_SVC_PANU 0x1115
#define BNEP_SVC_NAP 0x1116
#define BNEP_SVC_GN 0x1117
// Packet types
#define BNEP_GENERAL 0x00
#define BNEP_CONTROL 0x01
#define BNEP_COMPRESSED 0x02
#define BNEP_COMPRESSED_SRC_ONLY 0x03
#define BNEP_COMPRESSED_DST_ONLY 0x04
// Control types
#define BNEP_CMD_NOT_UNDERSTOOD 0x00
#define BNEP_SETUP_CONN_REQ 0x01
#define BNEP_SETUP_CONN_RSP 0x02
#define BNEP_FILTER_NET_TYPE_SET 0x03
#define BNEP_FILTER_NET_TYPE_RSP 0x04
#define BNEP_FILTER_MULTI_ADDR_SET 0x05
#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
// Extension types
#define BNEP_EXT_CONTROL 0x00
// Response messages
#define BNEP_SUCCESS 0x00
#define BNEP_CONN_INVALID_DST 0x01
#define BNEP_CONN_INVALID_SRC 0x02
#define BNEP_CONN_INVALID_SVC 0x03
#define BNEP_CONN_NOT_ALLOWED 0x04
#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
#define BNEP_FILTER_INVALID_RANGE 0x02
#define BNEP_FILTER_INVALID_MCADDR 0x02
#define BNEP_FILTER_LIMIT_REACHED 0x03
#define BNEP_FILTER_DENIED_SECURITY 0x04
// L2CAP settings
#define BNEP_MTU 1691
#define BNEP_PSM 0x0f
#define BNEP_FLUSH_TO 0xffff
#define BNEP_CONNECT_TO 15
#define BNEP_FILTER_TO 15
// Headers
#define BNEP_TYPE_MASK 0x7f
#define BNEP_EXT_HEADER 0x80
struct bnep_setup_conn_req {
__u8 type;
__u8 ctrl;
__u8 uuid_size;
__u8 service[0];
} __attribute__((packed));
struct bnep_set_filter_req {
__u8 type;
__u8 ctrl;
__u16 len;
__u8 list[0];
} __attribute__((packed));
struct bnep_control_rsp {
__u8 type;
__u8 ctrl;
__u16 resp;
} __attribute__((packed));
struct bnep_ext_hdr {
__u8 type;
__u8 len;
__u8 data[0];
} __attribute__((packed));
// Ioctl interface
#define BNEPCONADD 1
#define BNEPCONDEL 2
#define BNEPGETCONLIST 3
#define BNEPGETCONINFO 4
struct bnep_conadd_req {
int sock; // Connected socket
__u32 flags;
__u16 role;
char device[16]; // Name of the Ethernet device
};
struct bnep_condel_req {
__u32 flags;
__u8 dst[ETH_ALEN];
};
struct bnep_coninfo {
__u32 flags;
__u16 role;
__u16 state;
__u8 dst[ETH_ALEN];
char device[16];
};
struct bnep_conlist_req {
__u32 cnum;
struct bnep_coninfo *ci;
};
struct bnep_proto_filter {
__u16 start;
__u16 end;
};
int bnep_add_connection(struct bnep_conadd_req *req, struct socket *sock);
int bnep_del_connection(struct bnep_condel_req *req);
int bnep_get_conlist(struct bnep_conlist_req *req);
int bnep_get_coninfo(struct bnep_coninfo *ci);
// BNEP sessions
struct bnep_session {
struct list_head list;
unsigned int role;
unsigned long state;
unsigned long flags;
atomic_t killed;
struct ethhdr eh;
struct msghdr msg;
struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
u64 mc_filter;
struct socket *sock;
struct net_device dev;
struct net_device_stats stats;
};
int bnep_net_init(struct net_device *dev);
int bnep_sock_init(void);
int bnep_sock_cleanup(void);
static inline int bnep_mc_hash(__u8 *addr)
{
return (bnep_crc32(~0, addr, ETH_ALEN) >> 26);
}
#endif
This diff is collapsed.
/*
* Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com>
*
* FIXME: Remove in 2.5
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include "crc32.h"
#define CRCPOLY_BE 0x04c11db7
#define CRC_BE_BITS 8
static u32 *bnep_crc32_table;
/*
* This code is in the public domain; copyright abandoned.
* Liability for non-performance of this code is limited to the amount
* you paid for it. Since it is distributed for free, your refund will
* be very very small. If it breaks, you get to keep both pieces.
*/
u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len)
{
while (len--)
crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++];
return crc;
}
int __init bnep_crc32_init(void)
{
unsigned i, j;
u32 crc = 0x80000000;
bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
if (!bnep_crc32_table)
return -ENOMEM;
bnep_crc32_table[0] = 0;
for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
for (j = 0; j < i; j++)
bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j];
}
return 0;
}
void __exit bnep_crc32_cleanup(void)
{
if (bnep_crc32_table)
kfree(bnep_crc32_table);
bnep_crc32_table = NULL;
}
/*
* crc32.h
* See crc32.c for license and changes
*
* FIXME: Remove in 2.5
*/
int bnep_crc32_init(void);
void bnep_crc32_cleanup(void);
u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len);
/*
BNEP implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2001-2002 Inventel Systemes
Written 2001-2002 by
Clment Moreau <clement.moreau@inventel.fr>
David Libault <david.libault@inventel.fr>
Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
/*
* $Id: netdev.c,v 1.8 2002/08/04 21:23:58 maxk Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/socket.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/wait.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include "bnep.h"
#ifndef CONFIG_BNEP_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#endif
#define BNEP_TX_QUEUE_LEN 20
static int bnep_net_open(struct net_device *dev)
{
netif_start_queue(dev);
return 0;
}
static int bnep_net_close(struct net_device *dev)
{
netif_stop_queue(dev);
return 0;
}
static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
{
struct bnep_session *s = dev->priv;
return &s->stats;
}
static void bnep_net_set_mc_list(struct net_device *dev)
{
#ifdef CONFIG_BNEP_MC_FILTER
struct bnep_session *s = dev->priv;
struct sock *sk = s->sock->sk;
struct bnep_set_filter_req *r;
struct sk_buff *skb;
int size;
BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
skb = alloc_skb(size, GFP_ATOMIC);
if (!skb) {
BT_ERR("%s Multicast list allocation failed", dev->name);
return;
}
r = (void *) skb->data;
__skb_put(skb, sizeof(*r));
r->type = BNEP_CONTROL;
r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
u8 start[ETH_ALEN] = { 0x01 };
/* Request all addresses */
memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
r->len = htons(ETH_ALEN * 2);
} else {
struct dev_mc_list *dmi = dev->mc_list;
int i, len = skb->len;
if (dev->flags & IFF_BROADCAST) {
memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
}
/* FIXME: We should group addresses here. */
for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
dmi = dmi->next;
}
r->len = htons(skb->len - len);
}
skb_queue_tail(&sk->write_queue, skb);
wake_up_interruptible(sk->sleep);
#endif
}
static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
{
BT_DBG("%s", dev->name);
return 0;
}
static void bnep_net_timeout(struct net_device *dev)
{
BT_DBG("net_timeout");
netif_wake_queue(dev);
}
static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
return -EINVAL;
}
#ifdef CONFIG_BNEP_MC_FILTER
static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
{
struct ethhdr *eh = (void *) skb->data;
if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), (ulong *) &s->mc_filter))
return 1;
return 0;
}
#endif
#ifdef CONFIG_BNEP_PROTO_FILTER
/* Determine ether protocol. Based on eth_type_trans. */
static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
{
struct ethhdr *eh = (void *) skb->data;
if (ntohs(eh->h_proto) >= 1536)
return eh->h_proto;
if (get_unaligned((u16 *) skb->data) == 0xFFFF)
return htons(ETH_P_802_3);
return htons(ETH_P_802_2);
}
static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
{
u16 proto = bnep_net_eth_proto(skb);
struct bnep_proto_filter *f = s->proto_filter;
int i;
for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
if (proto >= f[i].start && proto <= f[i].end)
return 0;
}
BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
return 1;
}
#endif
static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bnep_session *s = dev->priv;
struct sock *sk = s->sock->sk;
BT_DBG("skb %p, dev %p", skb, dev);
#ifdef CONFIG_BNEP_MC_FILTER
if (bnep_net_mc_filter(skb, s)) {
kfree_skb(skb);
return 0;
}
#endif
#ifdef CONFIG_BNEP_PROTO_FILTER
if (bnep_net_proto_filter(skb, s)) {
kfree_skb(skb);
return 0;
}
#endif
/*
* We cannot send L2CAP packets from here as we are potentially in a bh.
* So we have to queue them and wake up session thread which is sleeping
* on the sk->sleep.
*/
dev->trans_start = jiffies;
skb_queue_tail(&sk->write_queue, skb);
wake_up_interruptible(sk->sleep);
if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) {
BT_DBG("tx queue is full");
/* Stop queuing.
* Session thread will do netif_wake_queue() */
netif_stop_queue(dev);
}
return 0;
}
int bnep_net_init(struct net_device *dev)
{
struct bnep_session *s = dev->priv;
memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
dev->addr_len = ETH_ALEN;
ether_setup(dev);
dev->open = bnep_net_open;
dev->stop = bnep_net_close;
dev->hard_start_xmit = bnep_net_xmit;
dev->get_stats = bnep_net_get_stats;
dev->do_ioctl = bnep_net_ioctl;
dev->set_mac_address = bnep_net_set_mac_addr;
dev->set_multicast_list = bnep_net_set_mc_list;
dev->watchdog_timeo = HZ * 2;
dev->tx_timeout = bnep_net_timeout;
return 0;
}
/*
BNEP implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2001-2002 Inventel Systemes
Written 2001-2002 by
David Libault <david.libault@inventel.fr>
Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
/*
* $Id: sock.c,v 1.4 2002/08/04 21:23:58 maxk Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/ioctl.h>
#include <linux/file.h>
#include <net/sock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include "bnep.h"
#ifndef CONFIG_BNEP_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#endif
static struct socket *sockfd_lookup(int fd, int *err)
{
struct file *file;
struct inode *inode;
struct socket *sock;
if (!(file = fget(fd))) {
*err = -EBADF;
return NULL;
}
inode = file->f_dentry->d_inode;
if (!inode->i_sock || !(sock = SOCKET_I(inode))) {
*err = -ENOTSOCK;
fput(file);
return NULL;
}
if (sock->file != file) {
printk(KERN_ERR "socki_lookup: socket file changed!\n");
sock->file = file;
}
return sock;
}
static int bnep_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
BT_DBG("sock %p sk %p", sock, sk);
if (!sk)
return 0;
sock_orphan(sk);
sock_put(sk);
MOD_DEC_USE_COUNT;
return 0;
}
static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct bnep_conlist_req cl;
struct bnep_conadd_req ca;
struct bnep_condel_req cd;
struct bnep_coninfo ci;
struct socket *nsock;
int err;
BT_DBG("cmd %x arg %lx", cmd, arg);
switch (cmd) {
case BNEPCONADD:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
return -EFAULT;
nsock = sockfd_lookup(ca.sock, &err);
if (!nsock)
return err;
if (nsock->sk->state != BT_CONNECTED)
return -EBADFD;
err = bnep_add_connection(&ca, nsock);
if (!err) {
if (copy_to_user((void *) arg, &ca, sizeof(ca)))
err = -EFAULT;
} else
fput(nsock->file);
return err;
case BNEPCONDEL:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
return -EFAULT;
return bnep_del_connection(&cd);
case BNEPGETCONLIST:
if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
return -EFAULT;
if (cl.cnum <= 0)
return -EINVAL;
err = bnep_get_conlist(&cl);
if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
return -EFAULT;
return err;
case BNEPGETCONINFO:
if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
return -EFAULT;
err = bnep_get_coninfo(&ci);
if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
return -EFAULT;
return err;
default:
return -EINVAL;
}
return 0;
}
static struct proto_ops bnep_sock_ops = {
.family = PF_BLUETOOTH,
.release = bnep_sock_release,
.ioctl = bnep_sock_ioctl,
.bind = sock_no_bind,
.getname = sock_no_getname,
.sendmsg = sock_no_sendmsg,
.recvmsg = sock_no_recvmsg,
.poll = sock_no_poll,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.mmap = sock_no_mmap
};
static int bnep_sock_create(struct socket *sock, int protocol)
{
struct sock *sk;
BT_DBG("sock %p", sock);
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
if (!(sk = bluez_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
return -ENOMEM;
sock->ops = &bnep_sock_ops;
MOD_INC_USE_COUNT;
sock->state = SS_UNCONNECTED;
sk->destruct = NULL;
sk->protocol = protocol;
return 0;
}
static struct net_proto_family bnep_sock_family_ops = {
.family = PF_BLUETOOTH,
.create = bnep_sock_create
};
int bnep_sock_init(void)
{
bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
return 0;
}
int bnep_sock_cleanup(void)
{
if (bluez_sock_unregister(BTPROTO_BNEP))
BT_ERR("Can't unregister BNEP socket");
return 0;
}
......@@ -73,7 +73,7 @@ void hci_acl_connect(struct hci_conn *conn)
bacpy(&cp.bdaddr, &conn->dst);
if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
inquiry_entry_age(ie) > INQUIRY_ENTRY_AGE_MAX) {
inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
cp.pscan_rep_mode = ie->info.pscan_rep_mode;
cp.pscan_mode = ie->info.pscan_mode;
cp.clock_offset = ie->info.clock_offset | __cpu_to_le16(0x8000);
......@@ -188,9 +188,6 @@ int hci_conn_del(struct hci_conn *conn)
acl->link = NULL;
hci_conn_put(acl);
}
/* Unacked frames */
hdev->sco_cnt += conn->sent;
} else {
struct hci_conn *sco = conn->link;
if (sco)
......@@ -220,7 +217,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
BT_DBG("%s -> %s", batostr(src), batostr(dst));
spin_lock_bh(&hdev_list_lock);
read_lock_bh(&hdev_list_lock);
list_for_each(p, &hdev_list) {
struct hci_dev *d;
......@@ -248,7 +245,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
if (hdev)
hci_dev_hold(hdev);
spin_unlock_bh(&hdev_list_lock);
read_unlock_bh(&hdev_list_lock);
return hdev;
}
......
......@@ -30,6 +30,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/types.h>
#include <linux/errno.h>
......@@ -66,7 +67,7 @@ rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
/* HCI device list */
LIST_HEAD(hdev_list);
spinlock_t hdev_list_lock;
rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED;
/* HCI protocols */
#define HCI_MAX_PROTO 2
......@@ -75,7 +76,6 @@ struct hci_proto *hci_proto[HCI_MAX_PROTO];
/* HCI notifiers list */
static struct notifier_block *hci_notifier;
/* ---- HCI notifications ---- */
int hci_register_notifier(struct notifier_block *nb)
......@@ -93,6 +93,32 @@ void hci_notify(struct hci_dev *hdev, int event)
notifier_call_chain(&hci_notifier, event, hdev);
}
/* ---- HCI hotplug support ---- */
#ifdef CONFIG_HOTPLUG
static int hci_run_hotplug(char *dev, char *action)
{
char *argv[3], *envp[5], dstr[20], astr[32];
sprintf(dstr, "DEVICE=%s", dev);
sprintf(astr, "ACTION=%s", action);
argv[0] = hotplug_path;
argv[1] = "bluetooth";
argv[2] = NULL;
envp[0] = "HOME=/";
envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp[2] = dstr;
envp[3] = astr;
envp[4] = NULL;
return call_usermodehelper(argv[0], argv, envp);
}
#else
#define hci_run_hotplug(A...)
#endif
/* ---- HCI requests ---- */
......@@ -270,7 +296,7 @@ struct hci_dev *hci_dev_get(int index)
if (index < 0)
return NULL;
spin_lock(&hdev_list_lock);
read_lock(&hdev_list_lock);
list_for_each(p, &hdev_list) {
hdev = list_entry(p, struct hci_dev, list);
if (hdev->id == index) {
......@@ -280,7 +306,7 @@ struct hci_dev *hci_dev_get(int index)
}
hdev = NULL;
done:
spin_unlock(&hdev_list_lock);
read_unlock(&hdev_list_lock);
return hdev;
}
......@@ -699,7 +725,7 @@ int hci_get_dev_list(unsigned long arg)
return -ENOMEM;
dr = dl->dev_req;
spin_lock_bh(&hdev_list_lock);
read_lock_bh(&hdev_list_lock);
list_for_each(p, &hdev_list) {
struct hci_dev *hdev;
hdev = list_entry(p, struct hci_dev, list);
......@@ -708,7 +734,7 @@ int hci_get_dev_list(unsigned long arg)
if (++n >= dev_num)
break;
}
spin_unlock_bh(&hdev_list_lock);
read_unlock_bh(&hdev_list_lock);
dl->dev_num = n;
size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
......@@ -768,7 +794,7 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->open || !hdev->close || !hdev->destruct)
return -EINVAL;
spin_lock_bh(&hdev_list_lock);
write_lock_bh(&hdev_list_lock);
/* Find first available device id */
list_for_each(p, &hdev_list) {
......@@ -807,11 +833,12 @@ int hci_register_dev(struct hci_dev *hdev)
atomic_set(&hdev->promisc, 0);
hci_notify(hdev, HCI_DEV_REG);
MOD_INC_USE_COUNT;
spin_unlock_bh(&hdev_list_lock);
write_unlock_bh(&hdev_list_lock);
hci_notify(hdev, HCI_DEV_REG);
hci_run_hotplug(hdev->name, "register");
return id;
}
......@@ -821,13 +848,15 @@ int hci_unregister_dev(struct hci_dev *hdev)
{
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
spin_lock_bh(&hdev_list_lock);
write_lock_bh(&hdev_list_lock);
list_del(&hdev->list);
spin_unlock_bh(&hdev_list_lock);
write_unlock_bh(&hdev_list_lock);
hci_dev_do_close(hdev);
hci_notify(hdev, HCI_DEV_UNREG);
hci_run_hotplug(hdev->name, "unregister");
hci_dev_put(hdev);
MOD_DEC_USE_COUNT;
......@@ -1103,14 +1132,13 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
{
struct conn_hash *h = &hdev->conn_hash;
struct hci_conn *conn = NULL;
int num = 0, min = 0xffff;
int num = 0, min = ~0;
struct list_head *p;
/* We don't have to lock device here. Connections are always
* added and removed with TX task disabled. */
list_for_each(p, &h->list) {
struct hci_conn *c;
c = list_entry(p, struct hci_conn, list);
if (c->type != type || c->state != BT_CONNECTED
......@@ -1118,14 +1146,15 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
continue;
num++;
if (c->sent < min || type == SCO_LINK) {
if (c->sent < min) {
min = c->sent;
conn = c;
}
}
if (conn) {
int q = hdev->acl_cnt / num;
int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
int q = cnt / num;
*quote = q ? q : 1;
} else
*quote = 0;
......@@ -1134,6 +1163,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
return conn;
}
static inline void hci_acl_tx_to(struct hci_dev *hdev)
{
struct conn_hash *h = &hdev->conn_hash;
struct list_head *p;
struct hci_conn *c;
BT_ERR("%s ACL tx timeout", hdev->name);
/* Kill stalled connections */
list_for_each(p, &h->list) {
c = list_entry(p, struct hci_conn, list);
if (c->type == ACL_LINK && c->sent) {
BT_ERR("%s killing stalled ACL connection %s",
hdev->name, batostr(&c->dst));
hci_acl_disconn(c, 0x13);
}
}
}
static inline void hci_sched_acl(struct hci_dev *hdev)
{
struct hci_conn *conn;
......@@ -1142,21 +1190,19 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > HZ*5) {
BT_ERR("%s ACL tx timeout", hdev->name);
hdev->acl_cnt++;
}
/* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */
if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
hci_acl_tx_to(hdev);
while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
while (quote && (skb = skb_dequeue(&conn->data_q))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
hci_send_frame(skb);
hdev->acl_last_tx = jiffies;
conn->sent++;
hdev->acl_cnt--;
quote--;
conn->sent++;
}
}
}
......@@ -1170,15 +1216,14 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
while ((conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
while (quote && (skb = skb_dequeue(&conn->data_q))) {
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
hci_send_frame(skb);
//conn->sent++;
//hdev->sco_cnt--;
quote--;
conn->sent++;
if (conn->sent == ~0)
conn->sent = 0;
}
}
}
......@@ -1205,7 +1250,6 @@ static void hci_tx_task(unsigned long arg)
read_unlock(&hci_task_lock);
}
/* ----- HCI RX task (incomming data proccessing) ----- */
/* ACL data packet */
......@@ -1367,9 +1411,6 @@ static void hci_cmd_task(unsigned long arg)
int hci_core_init(void)
{
/* Init locks */
spin_lock_init(&hdev_list_lock);
return 0;
}
......
......@@ -352,15 +352,12 @@ static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
hci_dev_lock(hdev);
acl = conn_hash_lookup_handle(hdev, handle);
if (!acl || !(sco = acl->link)) {
hci_dev_unlock(hdev);
break;
}
if (acl && (sco = acl->link)) {
sco->state = BT_CLOSED;
hci_proto_connect_cfm(sco, status);
hci_conn_del(sco);
}
hci_dev_unlock(hdev);
}
......
......@@ -86,7 +86,7 @@ static struct bluez_sock_list hci_sk_list = {
/* Send frame to RAW socket */
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
{
struct sock * sk;
struct sock *sk;
BT_DBG("hdev %p len %d", hdev, skb->len);
......@@ -105,13 +105,13 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
/* Apply filter */
flt = &hci_pi(sk)->filter;
if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
if (!test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
continue;
if (skb->pkt_type == HCI_EVENT_PKT) {
register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
if (!hci_test_bit(evt, &flt->event_mask))
if (!test_bit(evt, flt->event_mask))
continue;
if (flt->opcode && ((evt == EVT_CMD_COMPLETE &&
......@@ -249,7 +249,7 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
err = hci_sock_bound_ioctl(sk, cmd, arg);
release_sock(sk);
return err;
};
}
}
static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
......@@ -393,12 +393,12 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
err = -EPERM;
if (skb->pkt_type == HCI_COMMAND_PKT) {
__u16 opcode = __le16_to_cpu(*(__u16 *)skb->data);
__u16 ogf = cmd_opcode_ogf(opcode) - 1;
__u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS;
u16 opcode = __le16_to_cpu(*(__u16 *)skb->data);
u16 ogf = cmd_opcode_ogf(opcode) - 1;
u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS;
if (ogf > HCI_SFLT_MAX_OGF ||
!hci_test_bit(ocf, &hci_sec_filter.ocf_mask[ogf]))
!test_bit(ocf, hci_sec_filter.ocf_mask[ogf]))
goto drop;
} else
goto drop;
......@@ -420,8 +420,8 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
{
struct hci_ufilter uf = { .opcode = 0 };
struct sock *sk = sock->sk;
struct hci_filter flt = { opcode: 0 };
int err = 0, opt = 0;
BT_DBG("sk %p, opt %d", sk, optname);
......@@ -454,25 +454,32 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optva
break;
case HCI_FILTER:
len = MIN(len, sizeof(struct hci_filter));
if (copy_from_user(&flt, optval, len)) {
len = MIN(len, sizeof(uf));
if (copy_from_user(&uf, optval, len)) {
err = -EFAULT;
break;
}
if (!capable(CAP_NET_RAW)) {
flt.type_mask &= hci_sec_filter.type_mask;
flt.event_mask[0] &= hci_sec_filter.event_mask[0];
flt.event_mask[1] &= hci_sec_filter.event_mask[1];
uf.type_mask &= hci_sec_filter.type_mask;
uf.event_mask[0] &= *((u32 *) hci_sec_filter.event_mask + 0);
uf.event_mask[1] &= *((u32 *) hci_sec_filter.event_mask + 1);
}
memcpy(&hci_pi(sk)->filter, &flt, len);
{
struct hci_filter *f = &hci_pi(sk)->filter;
f->type_mask = uf.type_mask;
f->opcode = uf.opcode;
*((u32 *) f->event_mask + 0) = uf.event_mask[0];
*((u32 *) f->event_mask + 1) = uf.event_mask[0];
}
break;
default:
err = -ENOPROTOOPT;
break;
};
}
release_sock(sk);
return err;
......@@ -480,6 +487,7 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optva
int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
{
struct hci_ufilter uf;
struct sock *sk = sock->sk;
int len, opt;
......@@ -508,15 +516,24 @@ int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optva
break;
case HCI_FILTER:
len = MIN(len, sizeof(struct hci_filter));
if (copy_to_user(optval, &hci_pi(sk)->filter, len))
{
struct hci_filter *f = &hci_pi(sk)->filter;
uf.type_mask = f->type_mask;
uf.opcode = f->opcode;
uf.event_mask[0] = *((u32 *) f->event_mask + 0);
uf.event_mask[0] = *((u32 *) f->event_mask + 1);
}
len = MIN(len, sizeof(uf));
if (copy_to_user(optval, &uf, len))
return -EFAULT;
break;
default:
return -ENOPROTOOPT;
break;
};
}
return 0;
}
......
This diff is collapsed.
......@@ -105,7 +105,7 @@ int bterr(__u16 code)
return EACCES;
case 0x06:
return EINVAL;
return EBADE;
case 0x07:
return ENOMEM;
......
dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
bool ' RFCOMM TTY support' CONFIG_RFCOMM_TTY
fi
#
# Makefile for BNEP protocol
#
O_TARGET := rfcomm.o
obj-y := core.o sock.o crc.o
obj-$(CONFIG_RFCOMM_TTY) += tty.o
obj-m += $(O_TARGET)
include $(TOPDIR)/Rules.make
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment