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

Reply via email to