Don't try the patch below, there's yet a small bug. I'm yet adding link specific rtnetlink support, and will then send an update. The principle used below is yet valid.
Regards, Kurt On Mon, Jan 24, 2011 at 01:13:30PM +0100, Kurt Van Dijck wrote: > Date: Mon, 24 Jan 2011 13:13:30 +0100 > Subject: Re: struct sockaddr_can for j1939 > From: Kurt Van Dijck <[email protected]> > To: Oliver Hartkopp <[email protected]> > Cc: [email protected] > > Oliver, > > First example of rtnetlink message distribution for CAN sockets. > I did not (yet) do the userspace side, but I'm confident that is possible. > > 1 major remark I found is that rtnetlink has not left much room for > specifying addditional common attributes. See include/linux/can/core.h > > Any remarks on this? Does this meet your ideas? > > BTW, I changed all 'struct can_proto' to 'const struct proto', since that > struct may extend even more in the future if we continue like I propose now. > (ie. extensions for routing etc.). > > Thanks, > Kurt > --- > include/linux/can/core.h | 27 +++++++++- > net/can/af_can.c | 124 +++++++++++++++++++++++++++++++++++++++------ > net/can/bcm.c | 2 +- > net/can/raw.c | 2 +- > 4 files changed, 134 insertions(+), 21 deletions(-) > > diff --git a/include/linux/can/core.h b/include/linux/can/core.h > index a72a967..f8a79c3 100644 > --- a/include/linux/can/core.h > +++ b/include/linux/can/core.h > @@ -18,6 +18,7 @@ > #include <linux/can.h> > #include <linux/skbuff.h> > #include <linux/netdevice.h> > +#include <net/rtnetlink.h> > > #define CAN_VERSION "20090105" > > @@ -40,6 +41,28 @@ struct can_proto { > int protocol; > struct proto_ops *ops; > struct proto *prot; > + > + //const struct rtnl_af_ops *rtnl_link_ops; > + /* > + * hooks for rtnl hooks > + * for the *dump* functions, cb->args[0] is reserved > + * for use by af_can.c, so keep your fingers off. > + */ > + rtnl_doit_func rtnl_new_addr; > + rtnl_doit_func rtnl_del_addr; > + rtnl_dumpit_func rtnl_dump_addr; > +}; > + > +/* > + * this is quite a dirty hack: > + * reuse the second byte of a rtnetlink msg > + * to indicate the precise protocol. > + * The major problem is that is may conflict > + * with the prefixlen in struct ifaddrmsg. > + */ > +struct rtgencanmsg { > + unsigned char rtgen_family; > + unsigned char can_protocol; > }; > > /* > @@ -52,8 +75,8 @@ struct can_proto { > > /* function prototypes for the CAN networklayer core (af_can.c) */ > > -extern int can_proto_register(struct can_proto *cp); > -extern void can_proto_unregister(struct can_proto *cp); > +extern int can_proto_register(const struct can_proto *cp); > +extern void can_proto_unregister(const struct can_proto *cp); > > extern int can_rx_register(struct net_device *dev, canid_t can_id, > canid_t mask, > diff --git a/net/can/af_can.c b/net/can/af_can.c > index 702be5a..54729d7 100644 > --- a/net/can/af_can.c > +++ b/net/can/af_can.c > @@ -84,7 +84,7 @@ static DEFINE_SPINLOCK(can_rcvlists_lock); > static struct kmem_cache *rcv_cache __read_mostly; > > /* table of registered CAN protocols */ > -static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; > +static const struct can_proto *proto_tab[CAN_NPROTO]; > static DEFINE_SPINLOCK(proto_tab_lock); > > struct timer_list can_stattimer; /* timer for statistics update */ > @@ -92,6 +92,27 @@ struct s_stats can_stats; /* packet statistics */ > struct s_pstats can_pstats; /* receive list statistics */ > > /* > + * can protocol lookup > + */ > +static inline const struct can_proto *can_get_proto(int protocol) > +{ > + const struct can_proto *cp; > + > + if (protocol < 0 || protocol >= CAN_NPROTO) > + return ERR_PTR(-EINVAL); > + spin_lock(&proto_tab_lock); > + cp = proto_tab[protocol]; > + if (cp && !try_module_get(cp->prot->owner)) > + cp = ERR_PTR(-EPROTONOSUPPORT); > + spin_unlock(&proto_tab_lock); > + return cp; > +} > + > +static inline void can_put_proto(const struct can_proto *cp) > +{ > + module_put(cp->prot->owner); > +} > +/* > * af_can socket functions > */ > > @@ -118,14 +139,11 @@ static int can_create(struct net *net, struct socket > *sock, int protocol, > int kern) > { > struct sock *sk; > - struct can_proto *cp; > + const struct can_proto *cp; > int err = 0; > > sock->state = SS_UNCONNECTED; > > - if (protocol < 0 || protocol >= CAN_NPROTO) > - return -EINVAL; > - > if (!net_eq(net, &init_net)) > return -EAFNOSUPPORT; > > @@ -145,19 +163,14 @@ static int can_create(struct net *net, struct socket > *sock, int protocol, > } > #endif > > - spin_lock(&proto_tab_lock); > - cp = proto_tab[protocol]; > - if (cp && !try_module_get(cp->prot->owner)) > - cp = NULL; > - spin_unlock(&proto_tab_lock); > - > + cp = can_get_proto(protocol); > /* check for available protocol and correct usage */ > > - if (!cp) > - return -EPROTONOSUPPORT; > + if (IS_ERR(cp)) > + return PTR_ERR(cp); > > if (cp->type != sock->type) { > - err = -EPROTONOSUPPORT; > + err = -ESOCKTNOSUPPORT; > goto errout; > } > > @@ -182,7 +195,7 @@ static int can_create(struct net *net, struct socket > *sock, int protocol, > } > > errout: > - module_put(cp->prot->owner); > + can_put_proto(cp); > return err; > } > > @@ -678,7 +691,7 @@ drop: > * -EBUSY protocol already in use > * -ENOBUF if proto_register() fails > */ > -int can_proto_register(struct can_proto *cp) > +int can_proto_register(const struct can_proto *cp) > { > int proto = cp->protocol; > int err = 0; > @@ -718,7 +731,7 @@ EXPORT_SYMBOL(can_proto_register); > * can_proto_unregister - unregister CAN transport protocol > * @cp: pointer to CAN protocol structure > */ > -void can_proto_unregister(struct can_proto *cp) > +void can_proto_unregister(const struct can_proto *cp) > { > int proto = cp->protocol; > > @@ -809,6 +822,75 @@ static struct notifier_block can_netdev_notifier > __read_mostly = { > .notifier_call = can_notifier, > }; > > +/* > + * RTNETLINK > + */ > +static int can_rtnl_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void > *arg) > +{ > + int ret, protocol; > + const struct can_proto *cp; > + rtnl_doit_func fn; > + > + protocol = ((struct rtgencanmsg *)NLMSG_DATA(nlh))->can_protocol; > + cp = can_get_proto(protocol); > + if (IS_ERR(cp)) > + return PTR_ERR(cp); > + > + switch (nlh->nlmsg_type) { > + case RTM_NEWADDR: > + fn = cp->rtnl_new_addr; > + break; > + case RTM_DELADDR: > + fn = cp->rtnl_del_addr; > + break; > + default: > + fn = 0; > + break; > + } > + if (fn) > + ret = fn(skb, nlh, arg); > + else > + ret = -EPROTONOSUPPORT; > + can_put_proto(cp); > + return ret; > +} > + > +static int can_rtnl_dumpit(struct sk_buff *skb, struct netlink_callback *cb, > + int offset) > +{ > + int ret, j; > + const struct can_proto *cp; > + rtnl_dumpit_func fn; > + > + ret = 0; > + for (j = cb->args[0]; j < CAN_NPROTO; ++j) { > + /* save state */ > + cb->args[0] = j; > + cp = can_get_proto(j); > + if (IS_ERR(cp)) > + /* we are looping, any error is our own fault */ > + continue; > + fn = (rtnl_dumpit_func)(&((const uint8_t *)cp)[offset]); > + if (fn) > + ret = fn(skb, cb); > + else > + ret = 0; > + can_put_proto(cp); > + if (ret < 0) > + /* suspend this skb */ > + return ret; > + } > + return ret; > +} > + > +static int can_rtnl_dump_addr(struct sk_buff *skb, struct netlink_callback > *cb) > +{ > + return can_rtnl_dumpit(skb, cb, > + offsetof(struct can_proto, rtnl_dump_addr)); > +} > + > +/* exported init */ > + > static __init int can_init(void) > { > printk(banner); > @@ -834,6 +916,10 @@ static __init int can_init(void) > register_netdevice_notifier(&can_netdev_notifier); > dev_add_pack(&can_packet); > > + rtnl_register(PF_CAN, RTM_NEWADDR, can_rtnl_doit, NULL); > + rtnl_register(PF_CAN, RTM_DELADDR, can_rtnl_doit, NULL); > + rtnl_register(PF_CAN, RTM_GETADDR, NULL, can_rtnl_dump_addr); > + > return 0; > } > > @@ -844,6 +930,10 @@ static __exit void can_exit(void) > if (stats_timer) > del_timer(&can_stattimer); > > + rtnl_unregister(PF_CAN, RTM_NEWADDR); > + rtnl_unregister(PF_CAN, RTM_DELADDR); > + rtnl_unregister(PF_CAN, RTM_GETADDR); > + > can_remove_proc(); > > /* protocol unregister */ > diff --git a/net/can/bcm.c b/net/can/bcm.c > index 4f39d4c..65dcec5 100644 > --- a/net/can/bcm.c > +++ b/net/can/bcm.c > @@ -1596,7 +1596,7 @@ static struct proto bcm_proto __read_mostly = { > .init = bcm_init, > }; > > -static struct can_proto bcm_can_proto __read_mostly = { > +static const struct can_proto bcm_can_proto = { > .type = SOCK_DGRAM, > .protocol = CAN_BCM, > .ops = &bcm_ops, > diff --git a/net/can/raw.c b/net/can/raw.c > index e50c23a..9938dde 100644 > --- a/net/can/raw.c > +++ b/net/can/raw.c > @@ -769,7 +769,7 @@ static struct proto raw_proto __read_mostly = { > .init = raw_init, > }; > > -static struct can_proto raw_can_proto __read_mostly = { > +static const struct can_proto raw_can_proto = { > .type = SOCK_RAW, > .protocol = CAN_RAW, > .ops = &raw_ops, _______________________________________________ Socketcan-core mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-core
