diff options
| author | WANG Cong <xiyou.wangcong@gmail.com> | 2015-04-10 15:00:30 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-04-12 21:25:13 -0400 |
| commit | 7a6c8c34e5b71ac50e39588e20b39494a9e1d8e5 (patch) | |
| tree | 3593ce71a5a16427c35823a073072292a0d2a704 /net/ipv4 | |
| parent | 02d793c5bbebf2c750da03df4c950fc4e8e8a5a7 (diff) | |
fou: implement FOU_CMD_GET
Cc: Tom Herbert <tom@herbertland.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
| -rw-r--r-- | net/ipv4/fou.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index c244b1a65787..263710259774 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c | |||
| @@ -21,6 +21,7 @@ struct fou { | |||
| 21 | u8 protocol; | 21 | u8 protocol; |
| 22 | u8 flags; | 22 | u8 flags; |
| 23 | __be16 port; | 23 | __be16 port; |
| 24 | u16 type; | ||
| 24 | struct udp_offload udp_offloads; | 25 | struct udp_offload udp_offloads; |
| 25 | struct list_head list; | 26 | struct list_head list; |
| 26 | }; | 27 | }; |
| @@ -487,6 +488,8 @@ static int fou_create(struct net *net, struct fou_cfg *cfg, | |||
| 487 | goto error; | 488 | goto error; |
| 488 | } | 489 | } |
| 489 | 490 | ||
| 491 | fou->type = cfg->type; | ||
| 492 | |||
| 490 | udp_sk(sk)->encap_type = 1; | 493 | udp_sk(sk)->encap_type = 1; |
| 491 | udp_encap_enable(); | 494 | udp_encap_enable(); |
| 492 | 495 | ||
| @@ -617,6 +620,106 @@ static int fou_nl_cmd_rm_port(struct sk_buff *skb, struct genl_info *info) | |||
| 617 | return fou_destroy(net, &cfg); | 620 | return fou_destroy(net, &cfg); |
| 618 | } | 621 | } |
| 619 | 622 | ||
| 623 | static int fou_fill_info(struct fou *fou, struct sk_buff *msg) | ||
| 624 | { | ||
| 625 | if (nla_put_u8(msg, FOU_ATTR_AF, fou->sock->sk->sk_family) || | ||
| 626 | nla_put_be16(msg, FOU_ATTR_PORT, fou->port) || | ||
| 627 | nla_put_u8(msg, FOU_ATTR_IPPROTO, fou->protocol) || | ||
| 628 | nla_put_u8(msg, FOU_ATTR_TYPE, fou->type)) | ||
| 629 | return -1; | ||
| 630 | |||
| 631 | if (fou->flags & FOU_F_REMCSUM_NOPARTIAL) | ||
| 632 | if (nla_put_flag(msg, FOU_ATTR_REMCSUM_NOPARTIAL)) | ||
| 633 | return -1; | ||
| 634 | return 0; | ||
| 635 | } | ||
| 636 | |||
| 637 | static int fou_dump_info(struct fou *fou, u32 portid, u32 seq, | ||
| 638 | u32 flags, struct sk_buff *skb, u8 cmd) | ||
| 639 | { | ||
| 640 | void *hdr; | ||
| 641 | |||
| 642 | hdr = genlmsg_put(skb, portid, seq, &fou_nl_family, flags, cmd); | ||
| 643 | if (!hdr) | ||
| 644 | return -ENOMEM; | ||
| 645 | |||
| 646 | if (fou_fill_info(fou, skb) < 0) | ||
| 647 | goto nla_put_failure; | ||
| 648 | |||
| 649 | genlmsg_end(skb, hdr); | ||
| 650 | return 0; | ||
| 651 | |||
| 652 | nla_put_failure: | ||
| 653 | genlmsg_cancel(skb, hdr); | ||
| 654 | return -EMSGSIZE; | ||
| 655 | } | ||
| 656 | |||
| 657 | static int fou_nl_cmd_get_port(struct sk_buff *skb, struct genl_info *info) | ||
| 658 | { | ||
| 659 | struct net *net = genl_info_net(info); | ||
| 660 | struct fou_net *fn = net_generic(net, fou_net_id); | ||
| 661 | struct sk_buff *msg; | ||
| 662 | struct fou_cfg cfg; | ||
| 663 | struct fou *fout; | ||
| 664 | __be16 port; | ||
| 665 | int ret; | ||
| 666 | |||
| 667 | ret = parse_nl_config(info, &cfg); | ||
| 668 | if (ret) | ||
| 669 | return ret; | ||
| 670 | port = cfg.udp_config.local_udp_port; | ||
| 671 | if (port == 0) | ||
| 672 | return -EINVAL; | ||
| 673 | |||
| 674 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 675 | if (!msg) | ||
| 676 | return -ENOMEM; | ||
| 677 | |||
| 678 | ret = -ESRCH; | ||
| 679 | mutex_lock(&fn->fou_lock); | ||
| 680 | list_for_each_entry(fout, &fn->fou_list, list) { | ||
| 681 | if (port == fout->port) { | ||
| 682 | ret = fou_dump_info(fout, info->snd_portid, | ||
| 683 | info->snd_seq, 0, msg, | ||
| 684 | info->genlhdr->cmd); | ||
| 685 | break; | ||
| 686 | } | ||
| 687 | } | ||
| 688 | mutex_unlock(&fn->fou_lock); | ||
| 689 | if (ret < 0) | ||
| 690 | goto out_free; | ||
| 691 | |||
| 692 | return genlmsg_reply(msg, info); | ||
| 693 | |||
| 694 | out_free: | ||
| 695 | nlmsg_free(msg); | ||
| 696 | return ret; | ||
| 697 | } | ||
| 698 | |||
| 699 | static int fou_nl_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
| 700 | { | ||
| 701 | struct net *net = sock_net(skb->sk); | ||
| 702 | struct fou_net *fn = net_generic(net, fou_net_id); | ||
| 703 | struct fou *fout; | ||
| 704 | int idx = 0, ret; | ||
| 705 | |||
| 706 | mutex_lock(&fn->fou_lock); | ||
| 707 | list_for_each_entry(fout, &fn->fou_list, list) { | ||
| 708 | if (idx++ < cb->args[0]) | ||
| 709 | continue; | ||
| 710 | ret = fou_dump_info(fout, NETLINK_CB(cb->skb).portid, | ||
| 711 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
| 712 | skb, FOU_CMD_GET); | ||
| 713 | if (ret) | ||
| 714 | goto done; | ||
| 715 | } | ||
| 716 | mutex_unlock(&fn->fou_lock); | ||
| 717 | |||
| 718 | done: | ||
| 719 | cb->args[0] = idx; | ||
| 720 | return skb->len; | ||
| 721 | } | ||
| 722 | |||
| 620 | static const struct genl_ops fou_nl_ops[] = { | 723 | static const struct genl_ops fou_nl_ops[] = { |
| 621 | { | 724 | { |
| 622 | .cmd = FOU_CMD_ADD, | 725 | .cmd = FOU_CMD_ADD, |
| @@ -630,6 +733,12 @@ static const struct genl_ops fou_nl_ops[] = { | |||
| 630 | .policy = fou_nl_policy, | 733 | .policy = fou_nl_policy, |
| 631 | .flags = GENL_ADMIN_PERM, | 734 | .flags = GENL_ADMIN_PERM, |
| 632 | }, | 735 | }, |
| 736 | { | ||
| 737 | .cmd = FOU_CMD_GET, | ||
| 738 | .doit = fou_nl_cmd_get_port, | ||
| 739 | .dumpit = fou_nl_dump, | ||
| 740 | .policy = fou_nl_policy, | ||
| 741 | }, | ||
| 633 | }; | 742 | }; |
| 634 | 743 | ||
| 635 | size_t fou_encap_hlen(struct ip_tunnel_encap *e) | 744 | size_t fou_encap_hlen(struct ip_tunnel_encap *e) |
