can: Fix CAN_(EFF|RTR)_FLAG handling in can_filter
Due to a wrong safety check in af_can.c it was not possible to filter for SFF frames with a specific CAN identifier without getting the same selected CAN identifier from a received EFF frame also. This fix has a minimum (but user visible) impact on the CAN filter API and therefore the CAN version is set to a new date. Indeed the 'old' API is still working as-is. But when now setting CAN_(EFF|RTR)_FLAG in can_filter.can_mask you might get less traffic than before - but still the stuff that you expected to get for your defined filter ... Thanks to Kurt Van Dijck for pointing at this issue and for the review. Signed-off-by: Oliver Hartkopp <oliver@hartkopp.net> Acked-by: Kurt Van Dijck <kurt.van.dijck@eia.be> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
bd7df21920
Коммит
d253eee201
|
@ -19,7 +19,7 @@
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
|
|
||||||
#define CAN_VERSION "20071116"
|
#define CAN_VERSION "20081130"
|
||||||
|
|
||||||
/* increment this number each time you change some user-space interface */
|
/* increment this number each time you change some user-space interface */
|
||||||
#define CAN_ABI_VERSION "8"
|
#define CAN_ABI_VERSION "8"
|
||||||
|
|
|
@ -319,23 +319,52 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
|
||||||
return n ? d : NULL;
|
return n ? d : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find_rcv_list - determine optimal filterlist inside device filter struct
|
||||||
|
* @can_id: pointer to CAN identifier of a given can_filter
|
||||||
|
* @mask: pointer to CAN mask of a given can_filter
|
||||||
|
* @d: pointer to the device filter struct
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Returns the optimal filterlist to reduce the filter handling in the
|
||||||
|
* receive path. This function is called by service functions that need
|
||||||
|
* to register or unregister a can_filter in the filter lists.
|
||||||
|
*
|
||||||
|
* A filter matches in general, when
|
||||||
|
*
|
||||||
|
* <received_can_id> & mask == can_id & mask
|
||||||
|
*
|
||||||
|
* so every bit set in the mask (even CAN_EFF_FLAG, CAN_RTR_FLAG) describe
|
||||||
|
* relevant bits for the filter.
|
||||||
|
*
|
||||||
|
* The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
|
||||||
|
* filter for error frames (CAN_ERR_FLAG bit set in mask). For error frames
|
||||||
|
* there is a special filterlist and a special rx path filter handling.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* Pointer to optimal filterlist for the given can_id/mask pair.
|
||||||
|
* Constistency checked mask.
|
||||||
|
* Reduced can_id to have a preprocessed filter compare value.
|
||||||
|
*/
|
||||||
static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
|
static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
|
||||||
struct dev_rcv_lists *d)
|
struct dev_rcv_lists *d)
|
||||||
{
|
{
|
||||||
canid_t inv = *can_id & CAN_INV_FILTER; /* save flag before masking */
|
canid_t inv = *can_id & CAN_INV_FILTER; /* save flag before masking */
|
||||||
|
|
||||||
/* filter error frames */
|
/* filter for error frames in extra filterlist */
|
||||||
if (*mask & CAN_ERR_FLAG) {
|
if (*mask & CAN_ERR_FLAG) {
|
||||||
/* clear CAN_ERR_FLAG in list entry */
|
/* clear CAN_ERR_FLAG in filter entry */
|
||||||
*mask &= CAN_ERR_MASK;
|
*mask &= CAN_ERR_MASK;
|
||||||
return &d->rx[RX_ERR];
|
return &d->rx[RX_ERR];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ensure valid values in can_mask */
|
/* with cleared CAN_ERR_FLAG we have a simple mask/value filterpair */
|
||||||
if (*mask & CAN_EFF_FLAG)
|
|
||||||
*mask &= (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG);
|
#define CAN_EFF_RTR_FLAGS (CAN_EFF_FLAG | CAN_RTR_FLAG)
|
||||||
else
|
|
||||||
*mask &= (CAN_SFF_MASK | CAN_RTR_FLAG);
|
/* ensure valid values in can_mask for 'SFF only' frame filtering */
|
||||||
|
if ((*mask & CAN_EFF_FLAG) && !(*can_id & CAN_EFF_FLAG))
|
||||||
|
*mask &= (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS);
|
||||||
|
|
||||||
/* reduce condition testing at receive time */
|
/* reduce condition testing at receive time */
|
||||||
*can_id &= *mask;
|
*can_id &= *mask;
|
||||||
|
@ -348,15 +377,19 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
|
||||||
if (!(*mask))
|
if (!(*mask))
|
||||||
return &d->rx[RX_ALL];
|
return &d->rx[RX_ALL];
|
||||||
|
|
||||||
/* use extra filterset for the subscription of exactly *ONE* can_id */
|
/* extra filterlists for the subscription of a single non-RTR can_id */
|
||||||
if (*can_id & CAN_EFF_FLAG) {
|
if (((*mask & CAN_EFF_RTR_FLAGS) == CAN_EFF_RTR_FLAGS)
|
||||||
if (*mask == (CAN_EFF_MASK | CAN_EFF_FLAG)) {
|
&& !(*can_id & CAN_RTR_FLAG)) {
|
||||||
/* RFC: a use-case for hash-tables in the future? */
|
|
||||||
return &d->rx[RX_EFF];
|
if (*can_id & CAN_EFF_FLAG) {
|
||||||
|
if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) {
|
||||||
|
/* RFC: a future use-case for hash-tables? */
|
||||||
|
return &d->rx[RX_EFF];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS))
|
||||||
|
return &d->rx_sff[*can_id];
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (*mask == CAN_SFF_MASK)
|
|
||||||
return &d->rx_sff[*can_id];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default: filter via can_id/can_mask */
|
/* default: filter via can_id/can_mask */
|
||||||
|
|
|
@ -64,10 +64,11 @@
|
||||||
#define BCM_CAN_DLC_MASK 0x0F /* clean private flags in can_dlc by masking */
|
#define BCM_CAN_DLC_MASK 0x0F /* clean private flags in can_dlc by masking */
|
||||||
|
|
||||||
/* get best masking value for can_rx_register() for a given single can_id */
|
/* get best masking value for can_rx_register() for a given single can_id */
|
||||||
#define REGMASK(id) ((id & CAN_RTR_FLAG) | ((id & CAN_EFF_FLAG) ? \
|
#define REGMASK(id) ((id & CAN_EFF_FLAG) ? \
|
||||||
(CAN_EFF_MASK | CAN_EFF_FLAG) : CAN_SFF_MASK))
|
(CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \
|
||||||
|
(CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG))
|
||||||
|
|
||||||
#define CAN_BCM_VERSION "20080415"
|
#define CAN_BCM_VERSION CAN_VERSION
|
||||||
static __initdata const char banner[] = KERN_INFO
|
static __initdata const char banner[] = KERN_INFO
|
||||||
"can: broadcast manager protocol (rev " CAN_BCM_VERSION ")\n";
|
"can: broadcast manager protocol (rev " CAN_BCM_VERSION ")\n";
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче