On Tue, Apr 23, 2019 at 11:32:13AM +0200, Miroslav Lichvar wrote: > If those values I described above were in an array called ts_map > indexed by the RX filter enum, I think the check could just be: > > (ts_map[old_filter] & ts_map[new_filter]) == tsmap[old_filter] > > The individual bits would correspond to: > > PTP_V1_L4_SYNC > PTP_V1_L4_DELAY_REQ > PTP_V2_L4_SYNC > PTP_V2_L4_DELAY_REQ > PTP_V2_L2_SYNC > PTP_V2_L2_DELAY_REQ > NTP_ALL > > And the remaining RX filters would be combinations of those. > > -- Hi Miroslav, Richard,
Here is a draft patch with your idea. I haven't test it and it may has some issues. But the logic should looks like what you said. The copy_from/to_user is a little ugly, but I haven't come up with a more gentle way. Would you please help have a look at it and see which way we should use? Drop SIOCSHWTSTAMP in container or add a filter on macvlan(maybe only in container)? Thanks Hangbin diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 4a6be8fab884..0f87a42fc61c 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -824,18 +824,75 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu) return 0; } +int check_rx_filter(unsigned int new_filter, unsigned int old_filter) +{ + u8 ts_map[HWTSTAMP_FILTER_NTP_ALL]; + + memset(ts_map, 0, sizeof(ts_map)); + + ts_map[HWTSTAMP_FILTER_PTP_V1_L4_SYNC - 1] = 0x01; + ts_map[HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ - 1] = 0x02; + ts_map[HWTSTAMP_FILTER_PTP_V1_L4_EVENT - 1] = 0x03; + + ts_map[HWTSTAMP_FILTER_PTP_V2_L4_SYNC - 1] = 0x11; + ts_map[HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ - 1] = 0x12; + ts_map[HWTSTAMP_FILTER_PTP_V2_L4_EVENT - 1] = 0x13; + + ts_map[HWTSTAMP_FILTER_PTP_V2_SYNC - 1] = 0x31; + ts_map[HWTSTAMP_FILTER_PTP_V2_DELAY_REQ - 1] = 0x32; + ts_map[HWTSTAMP_FILTER_PTP_V2_EVENT - 1] = 0x33; + + ts_map[HWTSTAMP_FILTER_NTP_ALL - 1] = 0xF0; + ts_map[HWTSTAMP_FILTER_ALL - 1] = 0xFF; + + if ((ts_map[new_filter] & ts_map[old_filter]) == ts_map[old_filter]) + return 0; + else + return -EACCES; +} + static int macvlan_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct net_device *real_dev = macvlan_dev_real_dev(dev); const struct net_device_ops *ops = real_dev->netdev_ops; - struct ifreq ifrr; + unsigned int old_filter, new_filter, new_tx_type; + struct hwtstamp_config new_stmpconf, old_stmpconf; int err = -EOPNOTSUPP; + struct ifreq ifrr; + + /* Get new rx_filter */ + if (copy_from_user(&new_stmpconf, ifr->ifr_data, sizeof(new_stmpconf))) { + return -EFAULT; + } else { + new_tx_type = new_stmpconf.tx_type; + new_filter = new_stmpconf.rx_filter; + } + /* Get old rx_filter */ strncpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ); ifrr.ifr_ifru = ifr->ifr_ifru; + if (netif_device_present(real_dev) && ops->ndo_do_ioctl) + err = ops->ndo_do_ioctl(real_dev, &ifrr, SIOCGHWTSTAMP); + + if (!err && copy_from_user(&old_stmpconf, ifrr.ifr_data, sizeof(old_stmpconf))) + old_filter = old_stmpconf.rx_filter; + else + return err; + + /* Copy new data back */ + if (copy_to_user(ifrr.ifr_data, &new_stmpconf, sizeof(new_stmpconf))) + return -EFAULT; + switch (cmd) { case SIOCSHWTSTAMP: + if (new_tx_type != HWTSTAMP_TX_ON || + new_filter == HWTSTAMP_FILTER_SOME) + return err; + + err = check_rx_filter(new_filter, old_filter); + if (err) + break; case SIOCGHWTSTAMP: if (netif_device_present(real_dev) && ops->ndo_do_ioctl) err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd); -- 2.19.2