fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / bluetooth / cmtp / capi.c
index 7e03820..ab166b4 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-#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>
@@ -35,6 +33,7 @@
 #include <linux/socket.h>
 #include <linux/ioctl.h>
 #include <linux/file.h>
+#include <linux/wait.h>
 #include <net/sock.h>
 
 #include <linux/isdn/capilli.h>
 
 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
 {
-       struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
+       struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
 
        BT_DBG("session %p application %p appl %d", session, app, appl);
 
        if (!app)
                return NULL;
 
-       memset(app, 0, sizeof(*app));
-
        app->state = BT_OPEN;
        app->appl = appl;
 
@@ -139,6 +136,19 @@ static int cmtp_msgnum_get(struct cmtp_session *session)
        return session->msgnum;
 }
 
+static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
+{
+       struct cmtp_scb *scb = (void *) skb->cb;
+
+       BT_DBG("session %p skb %p len %d", session, skb, skb->len);
+
+       scb->id = -1;
+       scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
+
+       skb_queue_tail(&session->transmit, skb);
+
+       cmtp_schedule(session);
+}
 
 static void cmtp_send_interopmsg(struct cmtp_session *session,
                                        __u8 subcmd, __u16 appl, __u16 msgnum,
@@ -186,6 +196,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
 
        switch (CAPIMSG_SUBCOMMAND(skb->data)) {
        case CAPI_CONF:
+               if (skb->len < CAPI_MSG_BASELEN + 10)
+                       break;
+
                func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
                info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
 
@@ -216,6 +229,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
                        break;
 
                case CAPI_FUNCTION_GET_PROFILE:
+                       if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
+                               break;
+
                        controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
                        msgnum = CAPIMSG_MSGID(skb->data);
 
@@ -236,17 +252,26 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
                        break;
 
                case CAPI_FUNCTION_GET_MANUFACTURER:
+                       if (skb->len < CAPI_MSG_BASELEN + 15)
+                               break;
+
                        controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
 
                        if (!info && ctrl) {
+                               int len = min_t(uint, CAPI_MANUFACTURER_LEN,
+                                               skb->data[CAPI_MSG_BASELEN + 14]);
+
+                               memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
                                strncpy(ctrl->manu,
-                                       skb->data + CAPI_MSG_BASELEN + 15,
-                                       skb->data[CAPI_MSG_BASELEN + 14]);
+                                       skb->data + CAPI_MSG_BASELEN + 15, len);
                        }
 
                        break;
 
                case CAPI_FUNCTION_GET_VERSION:
+                       if (skb->len < CAPI_MSG_BASELEN + 32)
+                               break;
+
                        controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
 
                        if (!info && ctrl) {
@@ -259,13 +284,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
                        break;
 
                case CAPI_FUNCTION_GET_SERIAL_NUMBER:
+                       if (skb->len < CAPI_MSG_BASELEN + 17)
+                               break;
+
                        controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
 
                        if (!info && ctrl) {
+                               int len = min_t(uint, CAPI_SERIAL_LEN,
+                                               skb->data[CAPI_MSG_BASELEN + 16]);
+
                                memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
                                strncpy(ctrl->serial,
-                                       skb->data + CAPI_MSG_BASELEN + 17,
-                                       skb->data[CAPI_MSG_BASELEN + 16]);
+                                       skb->data + CAPI_MSG_BASELEN + 17, len);
                        }
 
                        break;
@@ -274,14 +304,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
                break;
 
        case CAPI_IND:
+               if (skb->len < CAPI_MSG_BASELEN + 6)
+                       break;
+
                func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
 
                if (func == CAPI_FUNCTION_LOOPBACK) {
+                       int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
+                                               skb->data[CAPI_MSG_BASELEN + 5]);
                        appl = CAPIMSG_APPID(skb->data);
                        msgnum = CAPIMSG_MSGID(skb->data);
                        cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
-                                               skb->data + CAPI_MSG_BASELEN + 6,
-                                               skb->data[CAPI_MSG_BASELEN + 5]);
+                                               skb->data + CAPI_MSG_BASELEN + 6, len);
                }
 
                break;
@@ -299,6 +333,9 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
 
        BT_DBG("session %p skb %p len %d", session, skb, skb->len);
 
+       if (skb->len < CAPI_MSG_BASELEN)
+               return;
+
        if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
                cmtp_recv_interopmsg(session, skb);
                return;
@@ -337,21 +374,6 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
        capi_ctr_handle_message(ctrl, appl, skb);
 }
 
-void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-{
-       struct cmtp_scb *scb = (void *) skb->cb;
-
-       BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
-       scb->id = -1;
-       scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
-
-       skb_queue_tail(&session->transmit, skb);
-
-       cmtp_schedule(session);
-}
-
-
 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 {
        BT_DBG("ctrl %p data %p", ctrl, data);
@@ -442,10 +464,8 @@ static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_
 
 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
 {
-       DECLARE_WAITQUEUE(wait, current);
        struct cmtp_session *session = ctrl->driverdata;
        struct cmtp_application *application;
-       unsigned long timeo = CMTP_INTEROP_TIMEOUT;
 
        BT_DBG("ctrl %p appl %d", ctrl, appl);
 
@@ -460,20 +480,8 @@ static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
        cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
                                CAPI_FUNCTION_RELEASE, NULL, 0);
 
-       add_wait_queue(&session->wait, &wait);
-       while (timeo) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (application->state == BT_CLOSED)
-                       break;
-
-               if (signal_pending(current))
-                       break;
-
-               timeo = schedule_timeout(timeo);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&session->wait, &wait);
+       wait_event_interruptible_timeout(session->wait,
+                       (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
 
        cmtp_application_del(session, application);
 }
@@ -493,7 +501,6 @@ static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
        application = cmtp_application_get(session, CMTP_APPLID, appl);
        if ((!application) || (application->state != BT_CONNECTED)) {
                BT_ERR("Can't find application with id %d", appl);
-               kfree_skb(skb);
                return CAPI_ILLAPPNR;
        }
 
@@ -544,9 +551,8 @@ static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, in
 
 int cmtp_attach_device(struct cmtp_session *session)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       unsigned long timeo = CMTP_INTEROP_TIMEOUT;
        unsigned char buf[4];
+       long ret;
 
        BT_DBG("session %p", session);
 
@@ -555,30 +561,17 @@ int cmtp_attach_device(struct cmtp_session *session)
        cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
                                CAPI_FUNCTION_GET_PROFILE, buf, 4);
 
-       add_wait_queue(&session->wait, &wait);
-       while (timeo) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (session->ncontroller)
-                       break;
-
-               if (signal_pending(current))
-                       break;
-
-               timeo = schedule_timeout(timeo);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&session->wait, &wait);
-
+       ret = wait_event_interruptible_timeout(session->wait,
+                       session->ncontroller, CMTP_INTEROP_TIMEOUT);
+       
        BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
 
-       if (!timeo)
+       if (!ret)
                return -ETIMEDOUT;
 
        if (!session->ncontroller)
                return -ENODEV;
 
-
        if (session->ncontroller > 1)
                BT_INFO("Setting up only CAPI controller 1");