]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/uwb/wlp/txrx.c
Merge branch 'master' into tk71
[mv-sheeva.git] / drivers / uwb / wlp / txrx.c
diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c
deleted file mode 100644 (file)
index 05dde44..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * Message exchange infrastructure
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: Docs
- *
- */
-
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/wlp.h>
-
-#include "wlp-internal.h"
-
-/*
- * Direct incoming association msg to correct parsing routine
- *
- * We only expect D1, E1, C1, C3 messages as new. All other incoming
- * association messages should form part of an established session that is
- * handled elsewhere.
- * The handling of these messages often require calling sleeping functions
- * - this cannot be done in interrupt context. We use the kernel's
- * workqueue to handle these messages.
- */
-static
-void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
-                          struct uwb_dev_addr *src)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_frame_assoc *assoc = (void *) skb->data;
-       struct wlp_assoc_frame_ctx *frame_ctx;
-
-       frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_ATOMIC);
-       if (frame_ctx == NULL) {
-               dev_err(dev, "WLP: Unable to allocate memory for association "
-                       "frame handling.\n");
-               kfree_skb(skb);
-               return;
-       }
-       frame_ctx->wlp = wlp;
-       frame_ctx->skb = skb;
-       frame_ctx->src = *src;
-       switch (assoc->type) {
-       case WLP_ASSOC_D1:
-               INIT_WORK(&frame_ctx->ws, wlp_handle_d1_frame);
-               schedule_work(&frame_ctx->ws);
-               break;
-       case WLP_ASSOC_E1:
-               kfree_skb(skb); /* Temporary until we handle it */
-               kfree(frame_ctx); /* Temporary until we handle it */
-               break;
-       case WLP_ASSOC_C1:
-               INIT_WORK(&frame_ctx->ws, wlp_handle_c1_frame);
-               schedule_work(&frame_ctx->ws);
-               break;
-       case WLP_ASSOC_C3:
-               INIT_WORK(&frame_ctx->ws, wlp_handle_c3_frame);
-               schedule_work(&frame_ctx->ws);
-               break;
-       default:
-               dev_err(dev, "Received unexpected association frame. "
-                       "Type = %d \n", assoc->type);
-               kfree_skb(skb);
-               kfree(frame_ctx);
-               break;
-       }
-}
-
-/*
- * Process incoming association frame
- *
- * Although it could be possible to deal with some incoming association
- * messages without creating a new session we are keeping things simple. We
- * do not accept new association messages if there is a session in progress
- * and the messages do not belong to that session.
- *
- * If an association message arrives that causes the creation of a session
- * (WLP_ASSOC_E1) while we are in the process of creating a session then we
- * rely on the neighbor mutex to protect the data. That is, the new session
- * will not be started until the previous is completed.
- */
-static
-void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
-                            struct uwb_dev_addr *src)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       struct wlp_frame_assoc *assoc = (void *) skb->data;
-       struct wlp_session *session = wlp->session;
-       u8 version;
-
-       if (wlp_get_version(wlp, &assoc->version, &version,
-                           sizeof(assoc->version)) < 0)
-               goto error;
-       if (version != WLP_VERSION) {
-               dev_err(dev, "Unsupported WLP version in association "
-                       "message.\n");
-               goto error;
-       }
-       if (session != NULL) {
-               /* Function that created this session is still holding the
-                * &wlp->mutex to protect this session. */
-               if (assoc->type == session->exp_message ||
-                   assoc->type == WLP_ASSOC_F0) {
-                       if (!memcmp(&session->neighbor_addr, src,
-                                  sizeof(*src))) {
-                               session->data = skb;
-                               (session->cb)(wlp);
-                       } else {
-                               dev_err(dev, "Received expected message from "
-                                       "unexpected source.  Expected message "
-                                       "%d or F0 from %02x:%02x, but received "
-                                       "it from %02x:%02x. Dropping.\n",
-                                       session->exp_message,
-                                       session->neighbor_addr.data[1],
-                                       session->neighbor_addr.data[0],
-                                       src->data[1], src->data[0]);
-                               goto error;
-                       }
-               } else {
-                       dev_err(dev, "Association already in progress. "
-                               "Dropping.\n");
-                       goto error;
-               }
-       } else {
-               wlp_direct_assoc_frame(wlp, skb, src);
-       }
-       return;
-error:
-       kfree_skb(skb);
-}
-
-/*
- * Verify incoming frame is from connected neighbor, prep to pass to WLP client
- *
- * Verification proceeds according to WLP 0.99 [7.3.1]. The source address
- * is used to determine which neighbor is sending the frame and the WSS tag
- * is used to know to which WSS the frame belongs (we only support one WSS
- * so this test is straight forward).
- * With the WSS found we need to ensure that we are connected before
- * allowing the exchange of data frames.
- */
-static
-int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb,
-                            struct uwb_dev_addr *src)
-{
-       struct device *dev = &wlp->rc->uwb_dev.dev;
-       int result = -EINVAL;
-       struct wlp_eda_node eda_entry;
-       struct wlp_frame_std_abbrv_hdr *hdr = (void *) skb->data;
-
-       /*verify*/
-       result = wlp_copy_eda_node(&wlp->eda, src, &eda_entry);
-       if (result < 0) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Incoming frame is from unknown "
-                               "neighbor %02x:%02x.\n", src->data[1],
-                               src->data[0]);
-               goto out;
-       }
-       if (hdr->tag != eda_entry.tag) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Tag of incoming frame from "
-                               "%02x:%02x does not match expected tag. "
-                               "Received 0x%02x, expected 0x%02x. \n",
-                               src->data[1], src->data[0], hdr->tag,
-                               eda_entry.tag);
-               result = -EINVAL;
-               goto out;
-       }
-       if (eda_entry.state != WLP_WSS_CONNECTED) {
-               if (printk_ratelimit())
-                       dev_err(dev, "WLP: Incoming frame from "
-                               "%02x:%02x does is not from connected WSS.\n",
-                               src->data[1], src->data[0]);
-               result = -EINVAL;
-               goto out;
-       }
-       /*prep*/
-       skb_pull(skb, sizeof(*hdr));
-out:
-       return result;
-}
-
-/*
- * Receive a WLP frame from device
- *
- * @returns: 1 if calling function should free the skb
- *           0 if it successfully handled skb and freed it
- *           0 if error occured, will free skb in this case
- */
-int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb,
-                     struct uwb_dev_addr *src)
-{
-       unsigned len = skb->len;
-       void *ptr = skb->data;
-       struct wlp_frame_hdr *hdr;
-       int result = 0;
-
-       if (len < sizeof(*hdr)) {
-               dev_err(dev, "Not enough data to parse WLP header.\n");
-               result = -EINVAL;
-               goto out;
-       }
-       hdr = ptr;
-       if (le16_to_cpu(hdr->mux_hdr) != WLP_PROTOCOL_ID) {
-               dev_err(dev, "Not a WLP frame type.\n");
-               result = -EINVAL;
-               goto out;
-       }
-       switch (hdr->type) {
-       case WLP_FRAME_STANDARD:
-               if (len < sizeof(struct wlp_frame_std_abbrv_hdr)) {
-                       dev_err(dev, "Not enough data to parse Standard "
-                               "WLP header.\n");
-                       goto out;
-               }
-               result = wlp_verify_prep_rx_frame(wlp, skb, src);
-               if (result < 0) {
-                       if (printk_ratelimit())
-                               dev_err(dev, "WLP: Verification of frame "
-                                       "from neighbor %02x:%02x failed.\n",
-                                       src->data[1], src->data[0]);
-                       goto out;
-               }
-               result = 1;
-               break;
-       case WLP_FRAME_ABBREVIATED:
-               dev_err(dev, "Abbreviated frame received. FIXME?\n");
-               kfree_skb(skb);
-               break;
-       case WLP_FRAME_CONTROL:
-               dev_err(dev, "Control frame received. FIXME?\n");
-               kfree_skb(skb);
-               break;
-       case WLP_FRAME_ASSOCIATION:
-               if (len < sizeof(struct wlp_frame_assoc)) {
-                       dev_err(dev, "Not enough data to parse Association "
-                               "WLP header.\n");
-                       goto out;
-               }
-               wlp_receive_assoc_frame(wlp, skb, src);
-               break;
-       default:
-               dev_err(dev, "Invalid frame received.\n");
-               result = -EINVAL;
-               break;
-       }
-out:
-       if (result < 0) {
-               kfree_skb(skb);
-               result = 0;
-       }
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_receive_frame);
-
-
-/*
- * Verify frame from network stack, prepare for further transmission
- *
- * @skb:   the socket buffer that needs to be prepared for transmission (it
- *         is in need of a WLP header). If this is a broadcast frame we take
- *         over the entire transmission.
- *         If it is a unicast the WSS connection should already be established
- *         and transmission will be done by the calling function.
- * @dst:   On return this will contain the device address to which the
- *         frame is destined.
- * @returns: 0 on success no tx : WLP header successfully applied to skb buffer,
- *                                calling function can proceed with tx
- *           1 on success with tx : WLP will take over transmission of this
- *                                  frame
- *           <0 on error
- *
- * The network stack (WLP client) is attempting to transmit a frame. We can
- * only transmit data if a local WSS is at least active (connection will be
- * done here if this is a broadcast frame and neighbor also has the WSS
- * active).
- *
- * The frame can be either broadcast or unicast. Broadcast in a WSS is
- * supported via multicast, but we don't support multicast yet (until
- * devices start to support MAB IEs). If a broadcast frame needs to be
- * transmitted it is treated as a unicast frame to each neighbor. In this
- * case the WLP takes over transmission of the skb and returns 1
- * to the caller to indicate so. Also, in this case, if a neighbor has the
- * same WSS activated but is not connected then the WSS connection will be
- * done at this time. The neighbor's virtual address will be learned at
- * this time.
- *
- * The destination address in a unicast frame is the virtual address of the
- * neighbor. This address only becomes known when a WSS connection is
- * established. We thus rely on a broadcast frame to trigger the setup of
- * WSS connections to all neighbors before we are able to send unicast
- * frames to them. This seems reasonable as IP would usually use ARP first
- * before any unicast frames are sent.
- *
- * If we are already connected to the neighbor (neighbor's virtual address
- * is known) we just prepare the WLP header and the caller will continue to
- * send the frame.
- *
- * A failure in this function usually indicates something that cannot be
- * fixed automatically. So, if this function fails (@return < 0) the calling
- * function should not retry to send the frame as it will very likely keep
- * failing.
- *
- */
-int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp,
-                        struct sk_buff *skb, struct uwb_dev_addr *dst)
-{
-       int result = -EINVAL;
-       struct ethhdr *eth_hdr = (void *) skb->data;
-
-       if (is_multicast_ether_addr(eth_hdr->h_dest)) {
-               result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb);
-               if (result < 0) {
-                       if (printk_ratelimit())
-                               dev_err(dev, "Unable to handle broadcast "
-                                       "frame from WLP client.\n");
-                       goto out;
-               }
-               dev_kfree_skb_irq(skb);
-               result = 1;
-               /* Frame will be transmitted by WLP. */
-       } else {
-               result = wlp_eda_for_virtual(&wlp->eda, eth_hdr->h_dest, dst,
-                                            wlp_wss_prep_hdr, skb);
-               if (unlikely(result < 0)) {
-                       if (printk_ratelimit())
-                               dev_err(dev, "Unable to prepare "
-                                       "skb for transmission. \n");
-                       goto out;
-               }
-       }
-out:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wlp_prepare_tx_frame);