| @@ -3714,6 +3714,110 @@ out: · 3713 unmodified lines |
| 3714 | 3714 | return 0; |
| 3715 | 3715 | } |
| 3716 | 3716 | |
| 3717 | +struct devlink_info_req { |
| 3718 | + struct sk_buff *msg; |
| 3719 | +}; |
| 3720 | + |
| 3721 | +int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name) |
| 3722 | +{ |
| 3723 | + return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name); |
| 3724 | +} |
| 3725 | +EXPORT_SYMBOL_GPL(devlink_info_driver_name_put); |
| 3726 | + |
| 3727 | +int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn) |
| 3728 | +{ |
| 3729 | + return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn); |
| 3730 | +} |
| 3731 | +EXPORT_SYMBOL_GPL(devlink_info_serial_number_put); |
| 3732 | + |
| 3733 | +static int |
| 3734 | +devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink, |
| 3735 | + enum devlink_command cmd, u32 portid, |
| 3736 | + u32 seq, int flags, struct netlink_ext_ack *extack) |
| 3737 | +{ |
| 3738 | + struct devlink_info_req req; |
| 3739 | + void *hdr; |
| 3740 | + int err; |
| 3741 | + |
| 3742 | + hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); |
| 3743 | + if (!hdr) |
| 3744 | + return -EMSGSIZE; |
| 3745 | + |
| 3746 | + err = -EMSGSIZE; |
| 3747 | + if (devlink_nl_put_handle(msg, devlink)) |
| 3748 | + goto err_cancel_msg; |
| 3749 | + |
| 3750 | + req.msg = msg; |
| 3751 | + err = devlink->ops->info_get(devlink, &req, extack); |
| 3752 | + if (err) |
| 3753 | + goto err_cancel_msg; |
| 3754 | + |
| 3755 | + genlmsg_end(msg, hdr); |
| 3756 | + return 0; |
| 3757 | + |
| 3758 | +err_cancel_msg: |
| 3759 | + genlmsg_cancel(msg, hdr); |
| 3760 | + return err; |
| 3761 | +} |
| 3762 | + |
| 3763 | +static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb, |
| 3764 | + struct genl_info *info) |
| 3765 | +{ |
| 3766 | + struct devlink *devlink = info->user_ptr[0]; |
| 3767 | + struct sk_buff *msg; |
| 3768 | + int err; |
| 3769 | + |
| 3770 | + if (!devlink->ops || !devlink->ops->info_get) |
| 3771 | + return -EOPNOTSUPP; |
| 3772 | + |
| 3773 | + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| 3774 | + if (!msg) |
| 3775 | + return -ENOMEM; |
| 3776 | + |
| 3777 | + err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET, |
| 3778 | + info->snd_portid, info->snd_seq, 0, |
| 3779 | + info->extack); |
| 3780 | + if (err) { |
| 3781 | + nlmsg_free(msg); |
| 3782 | + return err; |
| 3783 | + } |
| 3784 | + |
| 3785 | + return genlmsg_reply(msg, info); |
| 3786 | +} |
| 3787 | + |
| 3788 | +static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg, |
| 3789 | + struct netlink_callback *cb) |
| 3790 | +{ |
| 3791 | + struct devlink *devlink; |
| 3792 | + int start = cb->args[0]; |
| 3793 | + int idx = 0; |
| 3794 | + int err; |
| 3795 | + |
| 3796 | + mutex_lock(&devlink_mutex); |
| 3797 | + list_for_each_entry(devlink, &devlink_list, list) { |
| 3798 | + if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) |
| 3799 | + continue; |
| 3800 | + if (idx < start) { |
| 3801 | + idx++; |
| 3802 | + continue; |
| 3803 | + } |
| 3804 | + |
| 3805 | + mutex_lock(&devlink->lock); |
| 3806 | + err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET, |
| 3807 | + NETLINK_CB(cb->skb).portid, |
| 3808 | + cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 3809 | + cb->extack); |
| 3810 | + mutex_unlock(&devlink->lock); |
| 3811 | + if (err) |
| 3812 | + break; |
| 3813 | + idx++; |
| 3814 | + } |
| 3815 | + mutex_unlock(&devlink_mutex); |
| 3816 | + |
| 3817 | + cb->args[0] = idx; |
| 3818 | + return msg->len; |
| 3819 | +} |
| 3820 | + |
| 3717 | 3821 | static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { |
| 3718 | 3822 | [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, |
| 3719 | 3823 | [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, |
| @@ -3974,6 +4078,14 @@ static const struct genl_ops devlink_nl_ops[] = { · 254 unmodified lines |
| 3974 | 4078 | .flags = GENL_ADMIN_PERM, |
| 3975 | 4079 | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, |
| 3976 | 4080 | }, |
| 4081 | + { |
| 4082 | + .cmd = DEVLINK_CMD_INFO_GET, |
| 4083 | + .doit = devlink_nl_cmd_info_get_doit, |
| 4084 | + .dumpit = devlink_nl_cmd_info_get_dumpit, |
| 4085 | + .policy = devlink_nl_policy, |
| 4086 | + .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, |
| 4087 | + /* can be retrieved by unprivileged users */ |
| 4088 | + }, |
| 3977 | 4089 | }; |
| 3978 | 4090 | |
| 3979 | 4091 | static struct genl_family devlink_nl_family __ro_after_init = { |