linux/net/dsa/tag_mtk.c
<<
>>
Prefs
   1/*
   2 * Mediatek DSA Tag support
   3 * Copyright (C) 2017 Landen Chao <landen.chao@mediatek.com>
   4 *                    Sean Wang <sean.wang@mediatek.com>
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 and
   7 * only version 2 as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 */
  14
  15#include <linux/etherdevice.h>
  16
  17#include "dsa_priv.h"
  18
  19#define MTK_HDR_LEN             4
  20#define MTK_HDR_RECV_SOURCE_PORT_MASK   GENMASK(2, 0)
  21#define MTK_HDR_XMIT_DP_BIT_MASK        GENMASK(5, 0)
  22
  23static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
  24                                    struct net_device *dev)
  25{
  26        struct dsa_slave_priv *p = netdev_priv(dev);
  27        u8 *mtk_tag;
  28
  29        if (skb_cow_head(skb, MTK_HDR_LEN) < 0)
  30                return NULL;
  31
  32        skb_push(skb, MTK_HDR_LEN);
  33
  34        memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
  35
  36        /* Build the tag after the MAC Source Address */
  37        mtk_tag = skb->data + 2 * ETH_ALEN;
  38        mtk_tag[0] = 0;
  39        mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
  40        mtk_tag[2] = 0;
  41        mtk_tag[3] = 0;
  42
  43        return skb;
  44}
  45
  46static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
  47                                   struct packet_type *pt,
  48                                   struct net_device *orig_dev)
  49{
  50        struct dsa_switch_tree *dst = dev->dsa_ptr;
  51        struct dsa_switch *ds;
  52        int port;
  53        __be16 *phdr, hdr;
  54
  55        if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
  56                return NULL;
  57
  58        /* The MTK header is added by the switch between src addr
  59         * and ethertype at this point, skb->data points to 2 bytes
  60         * after src addr so header should be 2 bytes right before.
  61         */
  62        phdr = (__be16 *)(skb->data - 2);
  63        hdr = ntohs(*phdr);
  64
  65        /* Remove MTK tag and recalculate checksum. */
  66        skb_pull_rcsum(skb, MTK_HDR_LEN);
  67
  68        memmove(skb->data - ETH_HLEN,
  69                skb->data - ETH_HLEN - MTK_HDR_LEN,
  70                2 * ETH_ALEN);
  71
  72        /* This protocol doesn't support cascading multiple
  73         * switches so it's safe to assume the switch is first
  74         * in the tree.
  75         */
  76        ds = dst->ds[0];
  77        if (!ds)
  78                return NULL;
  79
  80        /* Get source port information */
  81        port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
  82        if (!ds->ports[port].netdev)
  83                return NULL;
  84
  85        skb->dev = ds->ports[port].netdev;
  86
  87        return skb;
  88}
  89
  90const struct dsa_device_ops mtk_netdev_ops = {
  91        .xmit   = mtk_tag_xmit,
  92        .rcv    = mtk_tag_rcv,
  93};
  94