]> err.no Git - linux-2.6/blobdiff - net/bluetooth/cmtp/capi.c
mac80211: fix fragmentation kludge
[linux-2.6] / net / bluetooth / cmtp / capi.c
index be04e9fb11f604639f92e447451098902a9977d6..3e9d5bb3fefb6de364353c62684efd5b7629e9d4 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    CMTP implementation for Linux Bluetooth stack (BlueZ).
    Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
 
    CMTP implementation for Linux Bluetooth stack (BlueZ).
    Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
 
    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
    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 
+   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.
 
    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 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
    SOFTWARE IS DISCLAIMED.
 */
 
@@ -196,6 +196,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
 
        switch (CAPIMSG_SUBCOMMAND(skb->data)) {
        case CAPI_CONF:
 
        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);
 
                func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
                info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
 
@@ -226,6 +229,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
                        break;
 
                case CAPI_FUNCTION_GET_PROFILE:
                        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);
 
                        controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
                        msgnum = CAPIMSG_MSGID(skb->data);
 
@@ -246,17 +252,26 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
                        break;
 
                case CAPI_FUNCTION_GET_MANUFACTURER:
                        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) {
                        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,
                                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:
                        }
 
                        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) {
                        controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
 
                        if (!info && ctrl) {
@@ -269,13 +284,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
                        break;
 
                case CAPI_FUNCTION_GET_SERIAL_NUMBER:
                        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) {
                        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,
                                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;
                        }
 
                        break;
@@ -284,14 +304,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
                break;
 
        case CAPI_IND:
                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) {
                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,
                        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;
                }
 
                break;
@@ -309,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);
 
 
        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;
        if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
                cmtp_recv_interopmsg(session, skb);
                return;
@@ -536,7 +563,7 @@ int cmtp_attach_device(struct cmtp_session *session)
 
        ret = wait_event_interruptible_timeout(session->wait,
                        session->ncontroller, CMTP_INTEROP_TIMEOUT);
 
        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 (!ret)
        BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
 
        if (!ret)