@@ -1751,6 +1751,18 @@ static struct neigh_table *neigh_find_table(int family)
1751
1751
return tbl ;
1752
1752
}
1753
1753
1754
+ const struct nla_policy nda_policy [NDA_MAX + 1 ] = {
1755
+ [NDA_DST ] = { .type = NLA_BINARY , .len = MAX_ADDR_LEN },
1756
+ [NDA_LLADDR ] = { .type = NLA_BINARY , .len = MAX_ADDR_LEN },
1757
+ [NDA_CACHEINFO ] = { .len = sizeof (struct nda_cacheinfo ) },
1758
+ [NDA_PROBES ] = { .type = NLA_U32 },
1759
+ [NDA_VLAN ] = { .type = NLA_U16 },
1760
+ [NDA_PORT ] = { .type = NLA_U16 },
1761
+ [NDA_VNI ] = { .type = NLA_U32 },
1762
+ [NDA_IFINDEX ] = { .type = NLA_U32 },
1763
+ [NDA_MASTER ] = { .type = NLA_U32 },
1764
+ };
1765
+
1754
1766
static int neigh_delete (struct sk_buff * skb , struct nlmsghdr * nlh ,
1755
1767
struct netlink_ext_ack * extack )
1756
1768
{
@@ -2711,6 +2723,186 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2711
2723
return skb -> len ;
2712
2724
}
2713
2725
2726
+ static int neigh_valid_get_req (const struct nlmsghdr * nlh ,
2727
+ struct neigh_table * * tbl ,
2728
+ void * * dst , int * dev_idx , u8 * ndm_flags ,
2729
+ struct netlink_ext_ack * extack )
2730
+ {
2731
+ struct nlattr * tb [NDA_MAX + 1 ];
2732
+ struct ndmsg * ndm ;
2733
+ int err , i ;
2734
+
2735
+ if (nlh -> nlmsg_len < nlmsg_msg_size (sizeof (* ndm ))) {
2736
+ NL_SET_ERR_MSG (extack , "Invalid header for neighbor get request" );
2737
+ return - EINVAL ;
2738
+ }
2739
+
2740
+ ndm = nlmsg_data (nlh );
2741
+ if (ndm -> ndm_pad1 || ndm -> ndm_pad2 || ndm -> ndm_state ||
2742
+ ndm -> ndm_type ) {
2743
+ NL_SET_ERR_MSG (extack , "Invalid values in header for neighbor get request" );
2744
+ return - EINVAL ;
2745
+ }
2746
+
2747
+ if (ndm -> ndm_flags & ~NTF_PROXY ) {
2748
+ NL_SET_ERR_MSG (extack , "Invalid flags in header for neighbor get request" );
2749
+ return - EINVAL ;
2750
+ }
2751
+
2752
+ err = nlmsg_parse_strict (nlh , sizeof (struct ndmsg ), tb , NDA_MAX ,
2753
+ nda_policy , extack );
2754
+ if (err < 0 )
2755
+ return err ;
2756
+
2757
+ * ndm_flags = ndm -> ndm_flags ;
2758
+ * dev_idx = ndm -> ndm_ifindex ;
2759
+ * tbl = neigh_find_table (ndm -> ndm_family );
2760
+ if (* tbl == NULL ) {
2761
+ NL_SET_ERR_MSG (extack , "Unsupported family in header for neighbor get request" );
2762
+ return - EAFNOSUPPORT ;
2763
+ }
2764
+
2765
+ for (i = 0 ; i <= NDA_MAX ; ++ i ) {
2766
+ if (!tb [i ])
2767
+ continue ;
2768
+
2769
+ switch (i ) {
2770
+ case NDA_DST :
2771
+ if (nla_len (tb [i ]) != (int )(* tbl )-> key_len ) {
2772
+ NL_SET_ERR_MSG (extack , "Invalid network address in neighbor get request" );
2773
+ return - EINVAL ;
2774
+ }
2775
+ * dst = nla_data (tb [i ]);
2776
+ break ;
2777
+ default :
2778
+ NL_SET_ERR_MSG (extack , "Unsupported attribute in neighbor get request" );
2779
+ return - EINVAL ;
2780
+ }
2781
+ }
2782
+
2783
+ return 0 ;
2784
+ }
2785
+
2786
+ static inline size_t neigh_nlmsg_size (void )
2787
+ {
2788
+ return NLMSG_ALIGN (sizeof (struct ndmsg ))
2789
+ + nla_total_size (MAX_ADDR_LEN ) /* NDA_DST */
2790
+ + nla_total_size (MAX_ADDR_LEN ) /* NDA_LLADDR */
2791
+ + nla_total_size (sizeof (struct nda_cacheinfo ))
2792
+ + nla_total_size (4 ) /* NDA_PROBES */
2793
+ + nla_total_size (1 ); /* NDA_PROTOCOL */
2794
+ }
2795
+
2796
+ static int neigh_get_reply (struct net * net , struct neighbour * neigh ,
2797
+ u32 pid , u32 seq )
2798
+ {
2799
+ struct sk_buff * skb ;
2800
+ int err = 0 ;
2801
+
2802
+ skb = nlmsg_new (neigh_nlmsg_size (), GFP_KERNEL );
2803
+ if (!skb )
2804
+ return - ENOBUFS ;
2805
+
2806
+ err = neigh_fill_info (skb , neigh , pid , seq , RTM_NEWNEIGH , 0 );
2807
+ if (err ) {
2808
+ kfree_skb (skb );
2809
+ goto errout ;
2810
+ }
2811
+
2812
+ err = rtnl_unicast (skb , net , pid );
2813
+ errout :
2814
+ return err ;
2815
+ }
2816
+
2817
+ static inline size_t pneigh_nlmsg_size (void )
2818
+ {
2819
+ return NLMSG_ALIGN (sizeof (struct ndmsg ))
2820
+ + nla_total_size (MAX_ADDR_LEN ); /* NDA_DST */
2821
+ + nla_total_size (1 ); /* NDA_PROTOCOL */
2822
+ }
2823
+
2824
+ static int pneigh_get_reply (struct net * net , struct pneigh_entry * neigh ,
2825
+ u32 pid , u32 seq , struct neigh_table * tbl )
2826
+ {
2827
+ struct sk_buff * skb ;
2828
+ int err = 0 ;
2829
+
2830
+ skb = nlmsg_new (pneigh_nlmsg_size (), GFP_KERNEL );
2831
+ if (!skb )
2832
+ return - ENOBUFS ;
2833
+
2834
+ err = pneigh_fill_info (skb , neigh , pid , seq , RTM_NEWNEIGH , 0 , tbl );
2835
+ if (err ) {
2836
+ kfree_skb (skb );
2837
+ goto errout ;
2838
+ }
2839
+
2840
+ err = rtnl_unicast (skb , net , pid );
2841
+ errout :
2842
+ return err ;
2843
+ }
2844
+
2845
+ static int neigh_get (struct sk_buff * in_skb , struct nlmsghdr * nlh ,
2846
+ struct netlink_ext_ack * extack )
2847
+ {
2848
+ struct net * net = sock_net (in_skb -> sk );
2849
+ struct net_device * dev = NULL ;
2850
+ struct neigh_table * tbl = NULL ;
2851
+ struct neighbour * neigh ;
2852
+ void * dst = NULL ;
2853
+ u8 ndm_flags = 0 ;
2854
+ int dev_idx = 0 ;
2855
+ int err ;
2856
+
2857
+ err = neigh_valid_get_req (nlh , & tbl , & dst , & dev_idx , & ndm_flags ,
2858
+ extack );
2859
+ if (err < 0 )
2860
+ return err ;
2861
+
2862
+ if (dev_idx ) {
2863
+ dev = __dev_get_by_index (net , dev_idx );
2864
+ if (!dev ) {
2865
+ NL_SET_ERR_MSG (extack , "Unknown device ifindex" );
2866
+ return - ENODEV ;
2867
+ }
2868
+ }
2869
+
2870
+ if (!dst ) {
2871
+ NL_SET_ERR_MSG (extack , "Network address not specified" );
2872
+ return - EINVAL ;
2873
+ }
2874
+
2875
+ if (ndm_flags & NTF_PROXY ) {
2876
+ struct pneigh_entry * pn ;
2877
+
2878
+ pn = pneigh_lookup (tbl , net , dst , dev , 0 );
2879
+ if (!pn ) {
2880
+ NL_SET_ERR_MSG (extack , "Proxy neighbour entry not found" );
2881
+ return - ENOENT ;
2882
+ }
2883
+ return pneigh_get_reply (net , pn , NETLINK_CB (in_skb ).portid ,
2884
+ nlh -> nlmsg_seq , tbl );
2885
+ }
2886
+
2887
+ if (!dev ) {
2888
+ NL_SET_ERR_MSG (extack , "No device specified" );
2889
+ return - EINVAL ;
2890
+ }
2891
+
2892
+ neigh = neigh_lookup (tbl , dst , dev );
2893
+ if (!neigh ) {
2894
+ NL_SET_ERR_MSG (extack , "Neighbour entry not found" );
2895
+ return - ENOENT ;
2896
+ }
2897
+
2898
+ err = neigh_get_reply (net , neigh , NETLINK_CB (in_skb ).portid ,
2899
+ nlh -> nlmsg_seq );
2900
+
2901
+ neigh_release (neigh );
2902
+
2903
+ return err ;
2904
+ }
2905
+
2714
2906
void neigh_for_each (struct neigh_table * tbl , void (* cb )(struct neighbour * , void * ), void * cookie )
2715
2907
{
2716
2908
int chain ;
@@ -3118,16 +3310,6 @@ static const struct seq_operations neigh_stat_seq_ops = {
3118
3310
};
3119
3311
#endif /* CONFIG_PROC_FS */
3120
3312
3121
- static inline size_t neigh_nlmsg_size (void )
3122
- {
3123
- return NLMSG_ALIGN (sizeof (struct ndmsg ))
3124
- + nla_total_size (MAX_ADDR_LEN ) /* NDA_DST */
3125
- + nla_total_size (MAX_ADDR_LEN ) /* NDA_LLADDR */
3126
- + nla_total_size (sizeof (struct nda_cacheinfo ))
3127
- + nla_total_size (4 ) /* NDA_PROBES */
3128
- + nla_total_size (1 ); /* NDA_PROTOCOL */
3129
- }
3130
-
3131
3313
static void __neigh_notify (struct neighbour * n , int type , int flags ,
3132
3314
u32 pid )
3133
3315
{
@@ -3511,7 +3693,7 @@ static int __init neigh_init(void)
3511
3693
{
3512
3694
rtnl_register (PF_UNSPEC , RTM_NEWNEIGH , neigh_add , NULL , 0 );
3513
3695
rtnl_register (PF_UNSPEC , RTM_DELNEIGH , neigh_delete , NULL , 0 );
3514
- rtnl_register (PF_UNSPEC , RTM_GETNEIGH , NULL , neigh_dump_info , 0 );
3696
+ rtnl_register (PF_UNSPEC , RTM_GETNEIGH , neigh_get , neigh_dump_info , 0 );
3515
3697
3516
3698
rtnl_register (PF_UNSPEC , RTM_GETNEIGHTBL , NULL , neightbl_dump_info ,
3517
3699
0 );
0 commit comments