@@ -3460,6 +3460,18 @@ void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change,
3460
3460
new_nsid , new_ifindex );
3461
3461
}
3462
3462
3463
+ static const struct nla_policy nda_policy [NDA_MAX + 1 ] = {
3464
+ [NDA_DST ] = { .type = NLA_BINARY , .len = MAX_ADDR_LEN },
3465
+ [NDA_LLADDR ] = { .type = NLA_BINARY , .len = MAX_ADDR_LEN },
3466
+ [NDA_CACHEINFO ] = { .len = sizeof (struct nda_cacheinfo ) },
3467
+ [NDA_PROBES ] = { .type = NLA_U32 },
3468
+ [NDA_VLAN ] = { .type = NLA_U16 },
3469
+ [NDA_PORT ] = { .type = NLA_U16 },
3470
+ [NDA_VNI ] = { .type = NLA_U32 },
3471
+ [NDA_IFINDEX ] = { .type = NLA_U32 },
3472
+ [NDA_MASTER ] = { .type = NLA_U32 },
3473
+ };
3474
+
3463
3475
static int nlmsg_populate_fdb_fill (struct sk_buff * skb ,
3464
3476
struct net_device * dev ,
3465
3477
u8 * addr , u16 vid , u32 pid , u32 seq ,
@@ -4021,6 +4033,160 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
4021
4033
return skb -> len ;
4022
4034
}
4023
4035
4036
+ static int valid_fdb_get_strict (const struct nlmsghdr * nlh ,
4037
+ struct nlattr * * tb , u8 * ndm_flags ,
4038
+ int * br_idx , int * brport_idx , u8 * * addr ,
4039
+ u16 * vid , struct netlink_ext_ack * extack )
4040
+ {
4041
+ struct ndmsg * ndm ;
4042
+ int err , i ;
4043
+
4044
+ if (nlh -> nlmsg_len < nlmsg_msg_size (sizeof (* ndm ))) {
4045
+ NL_SET_ERR_MSG (extack , "Invalid header for fdb get request" );
4046
+ return - EINVAL ;
4047
+ }
4048
+
4049
+ ndm = nlmsg_data (nlh );
4050
+ if (ndm -> ndm_pad1 || ndm -> ndm_pad2 || ndm -> ndm_state ||
4051
+ ndm -> ndm_type ) {
4052
+ NL_SET_ERR_MSG (extack , "Invalid values in header for fdb get request" );
4053
+ return - EINVAL ;
4054
+ }
4055
+
4056
+ if (ndm -> ndm_flags & ~(NTF_MASTER | NTF_SELF )) {
4057
+ NL_SET_ERR_MSG (extack , "Invalid flags in header for fdb get request" );
4058
+ return - EINVAL ;
4059
+ }
4060
+
4061
+ err = nlmsg_parse_strict (nlh , sizeof (struct ndmsg ), tb , NDA_MAX ,
4062
+ nda_policy , extack );
4063
+ if (err < 0 )
4064
+ return err ;
4065
+
4066
+ * ndm_flags = ndm -> ndm_flags ;
4067
+ * brport_idx = ndm -> ndm_ifindex ;
4068
+ for (i = 0 ; i <= NDA_MAX ; ++ i ) {
4069
+ if (!tb [i ])
4070
+ continue ;
4071
+
4072
+ switch (i ) {
4073
+ case NDA_MASTER :
4074
+ * br_idx = nla_get_u32 (tb [i ]);
4075
+ break ;
4076
+ case NDA_LLADDR :
4077
+ if (nla_len (tb [i ]) != ETH_ALEN ) {
4078
+ NL_SET_ERR_MSG (extack , "Invalid address in fdb get request" );
4079
+ return - EINVAL ;
4080
+ }
4081
+ * addr = nla_data (tb [i ]);
4082
+ break ;
4083
+ case NDA_VLAN :
4084
+ err = fdb_vid_parse (tb [i ], vid , extack );
4085
+ if (err )
4086
+ return err ;
4087
+ break ;
4088
+ case NDA_VNI :
4089
+ break ;
4090
+ default :
4091
+ NL_SET_ERR_MSG (extack , "Unsupported attribute in fdb get request" );
4092
+ return - EINVAL ;
4093
+ }
4094
+ }
4095
+
4096
+ return 0 ;
4097
+ }
4098
+
4099
+ static int rtnl_fdb_get (struct sk_buff * in_skb , struct nlmsghdr * nlh ,
4100
+ struct netlink_ext_ack * extack )
4101
+ {
4102
+ struct net_device * dev = NULL , * br_dev = NULL ;
4103
+ const struct net_device_ops * ops = NULL ;
4104
+ struct net * net = sock_net (in_skb -> sk );
4105
+ struct nlattr * tb [NDA_MAX + 1 ];
4106
+ struct sk_buff * skb ;
4107
+ int brport_idx = 0 ;
4108
+ u8 ndm_flags = 0 ;
4109
+ int br_idx = 0 ;
4110
+ u8 * addr = NULL ;
4111
+ u16 vid = 0 ;
4112
+ int err ;
4113
+
4114
+ err = valid_fdb_get_strict (nlh , tb , & ndm_flags , & br_idx ,
4115
+ & brport_idx , & addr , & vid , extack );
4116
+ if (err < 0 )
4117
+ return err ;
4118
+
4119
+ if (brport_idx ) {
4120
+ dev = __dev_get_by_index (net , brport_idx );
4121
+ if (!dev ) {
4122
+ NL_SET_ERR_MSG (extack , "Unknown device ifindex" );
4123
+ return - ENODEV ;
4124
+ }
4125
+ }
4126
+
4127
+ if (br_idx ) {
4128
+ if (dev ) {
4129
+ NL_SET_ERR_MSG (extack , "Master and device are mutually exclusive" );
4130
+ return - EINVAL ;
4131
+ }
4132
+
4133
+ br_dev = __dev_get_by_index (net , br_idx );
4134
+ if (!br_dev ) {
4135
+ NL_SET_ERR_MSG (extack , "Invalid master ifindex" );
4136
+ return - EINVAL ;
4137
+ }
4138
+ ops = br_dev -> netdev_ops ;
4139
+ }
4140
+
4141
+ if (dev ) {
4142
+ if (!ndm_flags || (ndm_flags & NTF_MASTER )) {
4143
+ if (!(dev -> priv_flags & IFF_BRIDGE_PORT )) {
4144
+ NL_SET_ERR_MSG (extack , "Device is not a bridge port" );
4145
+ return - EINVAL ;
4146
+ }
4147
+ br_dev = netdev_master_upper_dev_get (dev );
4148
+ if (!br_dev ) {
4149
+ NL_SET_ERR_MSG (extack , "Master of device not found" );
4150
+ return - EINVAL ;
4151
+ }
4152
+ ops = br_dev -> netdev_ops ;
4153
+ } else {
4154
+ if (!(ndm_flags & NTF_SELF )) {
4155
+ NL_SET_ERR_MSG (extack , "Missing NTF_SELF" );
4156
+ return - EINVAL ;
4157
+ }
4158
+ ops = dev -> netdev_ops ;
4159
+ }
4160
+ }
4161
+
4162
+ if (!br_dev && !dev ) {
4163
+ NL_SET_ERR_MSG (extack , "No device specified" );
4164
+ return - ENODEV ;
4165
+ }
4166
+
4167
+ if (!ops || !ops -> ndo_fdb_get ) {
4168
+ NL_SET_ERR_MSG (extack , "Fdb get operation not supported by device" );
4169
+ return - EOPNOTSUPP ;
4170
+ }
4171
+
4172
+ skb = nlmsg_new (NLMSG_GOODSIZE , GFP_KERNEL );
4173
+ if (!skb )
4174
+ return - ENOBUFS ;
4175
+
4176
+ if (br_dev )
4177
+ dev = br_dev ;
4178
+ err = ops -> ndo_fdb_get (skb , tb , dev , addr , vid ,
4179
+ NETLINK_CB (in_skb ).portid ,
4180
+ nlh -> nlmsg_seq , extack );
4181
+ if (err )
4182
+ goto out ;
4183
+
4184
+ return rtnl_unicast (skb , net , NETLINK_CB (in_skb ).portid );
4185
+ out :
4186
+ kfree_skb (skb );
4187
+ return err ;
4188
+ }
4189
+
4024
4190
static int brport_nla_put_flag (struct sk_buff * skb , u32 flags , u32 mask ,
4025
4191
unsigned int attrnum , unsigned int flag )
4026
4192
{
@@ -5081,7 +5247,7 @@ void __init rtnetlink_init(void)
5081
5247
5082
5248
rtnl_register (PF_BRIDGE , RTM_NEWNEIGH , rtnl_fdb_add , NULL , 0 );
5083
5249
rtnl_register (PF_BRIDGE , RTM_DELNEIGH , rtnl_fdb_del , NULL , 0 );
5084
- rtnl_register (PF_BRIDGE , RTM_GETNEIGH , NULL , rtnl_fdb_dump , 0 );
5250
+ rtnl_register (PF_BRIDGE , RTM_GETNEIGH , rtnl_fdb_get , rtnl_fdb_dump , 0 );
5085
5251
5086
5252
rtnl_register (PF_BRIDGE , RTM_GETLINK , NULL , rtnl_bridge_getlink , 0 );
5087
5253
rtnl_register (PF_BRIDGE , RTM_DELLINK , rtnl_bridge_dellink , NULL , 0 );
0 commit comments