]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/can/gw.c
Merge remote-tracking branch 'percpu/for-next'
[karo-tx-linux.git] / net / can / gw.c
index 2f291f961a170018f1464fb50f4faa272887a50d..3f9b0f3a281876e7d8ec7de0366ed98712759aad 100644 (file)
@@ -146,6 +146,7 @@ struct cgw_job {
                /* tbc */
        };
        u8 gwtype;
+       u8 limit_hops;
        u16 flags;
 };
 
@@ -402,6 +403,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
 
        /* put the incremented hop counter in the cloned skb */
        cgw_hops(nskb) = cgw_hops(skb) + 1;
+
+       /* first processing of this CAN frame -> adjust to private hop limit */
+       if (gwj->limit_hops && cgw_hops(nskb) == 1)
+               cgw_hops(nskb) = max_hops - gwj->limit_hops + 1;
+
        nskb->dev = gwj->dst.dev;
 
        /* pointer to modifiable CAN frame */
@@ -509,6 +515,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
 
        /* check non default settings of attributes */
 
+       if (gwj->limit_hops) {
+               if (nla_put_u8(skb, CGW_LIM_HOPS, gwj->limit_hops) < 0)
+                       goto cancel;
+       }
+
        if (gwj->mod.modtype.and) {
                memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
                mb.modtype = gwj->mod.modtype.and;
@@ -606,11 +617,12 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = {
        [CGW_SRC_IF]    = { .type = NLA_U32 },
        [CGW_DST_IF]    = { .type = NLA_U32 },
        [CGW_FILTER]    = { .len = sizeof(struct can_filter) },
+       [CGW_LIM_HOPS]  = { .type = NLA_U8 },
 };
 
 /* check for common and gwtype specific attributes */
 static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
-                         u8 gwtype, void *gwtypeattr)
+                         u8 gwtype, void *gwtypeattr, u8 *limhops)
 {
        struct nlattr *tb[CGW_MAX+1];
        struct cgw_frame_mod mb;
@@ -625,6 +637,13 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
        if (err < 0)
                return err;
 
+       if (tb[CGW_LIM_HOPS]) {
+               *limhops = nla_get_u8(tb[CGW_LIM_HOPS]);
+
+               if (*limhops < 1 || *limhops > max_hops)
+                       return -EINVAL;
+       }
+
        /* check for AND/OR/XOR/SET modifications */
 
        if (tb[CGW_MOD_AND]) {
@@ -782,6 +801,7 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
 {
        struct rtcanmsg *r;
        struct cgw_job *gwj;
+       u8 limhops = 0;
        int err = 0;
 
        if (!capable(CAP_NET_ADMIN))
@@ -808,7 +828,8 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
        gwj->flags = r->flags;
        gwj->gwtype = r->gwtype;
 
-       err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw);
+       err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw,
+                            &limhops);
        if (err < 0)
                goto out;
 
@@ -836,6 +857,8 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
        if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops)
                goto put_src_dst_out;
 
+       gwj->limit_hops = limhops;
+
        ASSERT_RTNL();
 
        err = cgw_register_filter(gwj);
@@ -867,13 +890,14 @@ static void cgw_remove_all_jobs(void)
        }
 }
 
-static int cgw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
+static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        struct cgw_job *gwj = NULL;
        struct hlist_node *nx;
        struct rtcanmsg *r;
        struct cf_mod mod;
        struct can_can_gw ccgw;
+       u8 limhops = 0;
        int err = 0;
 
        if (!capable(CAP_NET_ADMIN))
@@ -890,7 +914,7 @@ static int cgw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
        if (r->gwtype != CGW_TYPE_CAN_CAN)
                return -EINVAL;
 
-       err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw);
+       err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops);
        if (err < 0)
                return err;
 
@@ -910,6 +934,9 @@ static int cgw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
                if (gwj->flags != r->flags)
                        continue;
 
+               if (gwj->limit_hops != limhops)
+                       continue;
+
                if (memcmp(&gwj->mod, &mod, sizeof(mod)))
                        continue;