Commit d876e551 authored by Maksim Krasnyanskiy's avatar Maksim Krasnyanskiy

RFCOMM core API extensions. Improved /proc/bluetooth/rfcomm format.

RFCOMM socket locking fixes. 
Fix typo in rfcomm_pi() macro, no more oopses on socket destruction. 
parent 730e1a09
...@@ -268,6 +268,7 @@ struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst); ...@@ -268,6 +268,7 @@ 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); 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_del(struct rfcomm_session *s);
void rfcomm_session_close(struct rfcomm_session *s, int err); void rfcomm_session_close(struct rfcomm_session *s, int err);
void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
static inline void rfcomm_session_hold(struct rfcomm_session *s) static inline void rfcomm_session_hold(struct rfcomm_session *s)
{ {
...@@ -290,7 +291,7 @@ struct sockaddr_rc { ...@@ -290,7 +291,7 @@ struct sockaddr_rc {
u8 rc_channel; u8 rc_channel;
}; };
#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) &sk->protinfo) #define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk->protinfo)
struct rfcomm_pinfo { struct rfcomm_pinfo {
struct rfcomm_dlc *dlc; struct rfcomm_dlc *dlc;
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/proc_fs.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -572,6 +573,15 @@ struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int * ...@@ -572,6 +573,15 @@ struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *
return NULL; return NULL;
} }
void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
{
struct sock *sk = s->sock->sk;
if (src)
bacpy(src, &bluez_sk(sk)->src);
if (dst)
bacpy(dst, &bluez_sk(sk)->dst);
}
/* ---- RFCOMM frame sending ---- */ /* ---- RFCOMM frame sending ---- */
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len) static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
{ {
...@@ -1674,6 +1684,63 @@ static int rfcomm_run(void *unused) ...@@ -1674,6 +1684,63 @@ static int rfcomm_run(void *unused)
return 0; return 0;
} }
/* ---- Proc fs support ---- */
static int rfcomm_dlc_dump(char *buf)
{
struct rfcomm_session *s;
struct sock *sk;
struct list_head *p, *pp;
char *ptr = buf;
rfcomm_lock();
list_for_each(p, &session_list) {
s = list_entry(p, struct rfcomm_session, list);
sk = s->sock->sk;
list_for_each(pp, &s->dlcs) {
struct rfcomm_dlc *d;
d = list_entry(pp, struct rfcomm_dlc, list);
ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst),
d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
}
}
rfcomm_unlock();
return ptr - buf;
}
extern int rfcomm_sock_dump(char *buf);
static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
{
char *ptr = buf;
int len;
BT_DBG("count %d, offset %ld", count, offset);
ptr += rfcomm_dlc_dump(ptr);
ptr += rfcomm_sock_dump(ptr);
len = ptr - buf;
if (len <= count + offset)
*eof = 1;
*start = buf + offset;
len -= offset;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
}
/* ---- Initialization ---- */
int __init rfcomm_init(void) int __init rfcomm_init(void)
{ {
kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
...@@ -1684,6 +1751,8 @@ int __init rfcomm_init(void) ...@@ -1684,6 +1751,8 @@ int __init rfcomm_init(void)
rfcomm_init_ttys(); rfcomm_init_ttys();
#endif #endif
create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
BT_INFO("BlueZ RFCOMM ver %s", VERSION); BT_INFO("BlueZ RFCOMM ver %s", VERSION);
BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>"); BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>"); BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
...@@ -1701,6 +1770,8 @@ void rfcomm_cleanup(void) ...@@ -1701,6 +1770,8 @@ void rfcomm_cleanup(void)
while (atomic_read(&running)) while (atomic_read(&running))
schedule(); schedule();
remove_proc_entry("bluetooth/rfcomm", NULL);
#ifdef CONFIG_BLUEZ_RFCOMM_TTY #ifdef CONFIG_BLUEZ_RFCOMM_TTY
rfcomm_cleanup_ttys(); rfcomm_cleanup_ttys();
#endif #endif
......
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/list.h> #include <linux/list.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -83,7 +82,6 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb) ...@@ -83,7 +82,6 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
rfcomm_dlc_throttle(d); rfcomm_dlc_throttle(d);
return;
} }
static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
...@@ -94,22 +92,26 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) ...@@ -94,22 +92,26 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
BT_DBG("dlc %p state %ld err %d", d, d->state, err); BT_DBG("dlc %p state %ld err %d", d, d->state, err);
bh_lock_sock(sk);
if (err) if (err)
sk->err = err; sk->err = err;
sk->state = d->state; sk->state = d->state;
parent = bluez_sk(sk)->parent; parent = bluez_sk(sk)->parent;
if (!parent) if (!parent) {
if (d->state == BT_CONNECTED)
rfcomm_session_getaddr(d->session, &bluez_sk(sk)->src, NULL);
sk->state_change(sk); sk->state_change(sk);
else } else
parent->data_ready(parent, 0); parent->data_ready(parent, 0);
return;
bh_unlock_sock(sk);
} }
static void rfcomm_sk_modem_status(struct rfcomm_dlc *d, int v24_sig) static void rfcomm_sk_modem_status(struct rfcomm_dlc *d, int v24_sig)
{ {
BT_DBG("dlc %p v24_sig 0x%02x", d, v24_sig); BT_DBG("dlc %p v24_sig 0x%02x", d, v24_sig);
return; return;
} }
...@@ -374,6 +376,7 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a ...@@ -374,6 +376,7 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
sk->state = BT_CONNECT; sk->state = BT_CONNECT;
bacpy(&bluez_sk(sk)->dst, &sa->rc_bdaddr); bacpy(&bluez_sk(sk)->dst, &sa->rc_bdaddr);
rfcomm_pi(sk)->channel = sa->rc_channel;
err = rfcomm_dlc_open(d, &bluez_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel); err = rfcomm_dlc_open(d, &bluez_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
if (!err) if (!err)
...@@ -655,7 +658,6 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) ...@@ -655,7 +658,6 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how)
return 0; return 0;
} }
static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -735,14 +737,16 @@ static int rfcomm_sock_release(struct socket *sock) ...@@ -735,14 +737,16 @@ static int rfcomm_sock_release(struct socket *sock)
*/ */
int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d) int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
{ {
struct bluez_sock *bsk = bluez_sk(s->sock->sk);
struct sock *sk, *parent; struct sock *sk, *parent;
bdaddr_t src, dst;
int result = 0; int result = 0;
BT_DBG("session %p channel %d", s, channel); BT_DBG("session %p channel %d", s, channel);
rfcomm_session_getaddr(s, &src, &dst);
/* Check if we have socket listening on channel */ /* Check if we have socket listening on channel */
parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &bsk->src); parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
if (!parent) if (!parent)
return 0; return 0;
...@@ -757,8 +761,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * ...@@ -757,8 +761,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
goto done; goto done;
rfcomm_sock_init(sk, parent); rfcomm_sock_init(sk, parent);
bacpy(&bluez_sk(sk)->src, &bsk->src); bacpy(&bluez_sk(sk)->src, &src);
bacpy(&bluez_sk(sk)->dst, &bsk->dst); bacpy(&bluez_sk(sk)->dst, &dst);
rfcomm_pi(sk)->channel = channel; rfcomm_pi(sk)->channel = channel;
sk->state = BT_CONFIG; sk->state = BT_CONFIG;
...@@ -774,8 +778,9 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * ...@@ -774,8 +778,9 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
} }
/* ---- Proc fs support ---- */ /* ---- Proc fs support ---- */
static int rfcomm_sock_dump(char *buf, struct bluez_sock_list *list) int rfcomm_sock_dump(char *buf)
{ {
struct bluez_sock_list *list = &rfcomm_sk_list;
struct rfcomm_pinfo *pi; struct rfcomm_pinfo *pi;
struct sock *sk; struct sock *sk;
char *ptr = buf; char *ptr = buf;
...@@ -784,42 +789,16 @@ static int rfcomm_sock_dump(char *buf, struct bluez_sock_list *list) ...@@ -784,42 +789,16 @@ static int rfcomm_sock_dump(char *buf, struct bluez_sock_list *list)
for (sk = list->head; sk; sk = sk->next) { for (sk = list->head; sk; sk = sk->next) {
pi = rfcomm_pi(sk); pi = rfcomm_pi(sk);
ptr += sprintf(ptr, "%s %s %d %d\n", ptr += sprintf(ptr, "sk %s %s %d %d\n",
batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst), batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst),
sk->state, rfcomm_pi(sk)->channel); sk->state, rfcomm_pi(sk)->channel);
} }
write_unlock_bh(&list->lock); write_unlock_bh(&list->lock);
ptr += sprintf(ptr, "\n");
return ptr - buf; return ptr - buf;
} }
static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
{
char *ptr = buf;
int len;
BT_DBG("count %d, offset %ld", count, offset);
ptr += rfcomm_sock_dump(ptr, &rfcomm_sk_list);
len = ptr - buf;
if (len <= count + offset)
*eof = 1;
*start = buf + offset;
len -= offset;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
}
static struct proto_ops rfcomm_sock_ops = { static struct proto_ops rfcomm_sock_ops = {
.family = PF_BLUETOOTH, .family = PF_BLUETOOTH,
.release = rfcomm_sock_release, .release = rfcomm_sock_release,
...@@ -853,7 +832,6 @@ int rfcomm_init_sockets(void) ...@@ -853,7 +832,6 @@ int rfcomm_init_sockets(void)
return err; return err;
} }
create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
return 0; return 0;
} }
...@@ -861,8 +839,6 @@ void rfcomm_cleanup_sockets(void) ...@@ -861,8 +839,6 @@ void rfcomm_cleanup_sockets(void)
{ {
int err; int err;
remove_proc_entry("bluetooth/rfcomm", NULL);
/* Unregister socket, protocol and notifier */ /* Unregister socket, protocol and notifier */
if ((err = bluez_sock_unregister(BTPROTO_RFCOMM))) if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
BT_ERR("Can't unregister RFCOMM socket layer %d", err); BT_ERR("Can't unregister RFCOMM socket layer %d", err);
......
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