1 /* 2 * Copyright Samuel Mendoza-Jonas, IBM Corporation 2018. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/kernel.h> 12 #include <linux/if_arp.h> 13 #include <linux/rtnetlink.h> 14 #include <linux/etherdevice.h> 15 #include <linux/module.h> 16 #include <net/genetlink.h> 17 #include <net/ncsi.h> 18 #include <linux/skbuff.h> 19 #include <net/sock.h> 20 #include <uapi/linux/ncsi.h> 21 22 #include "internal.h" 23 #include "ncsi-netlink.h" 24 25 static struct genl_family ncsi_genl_family; 26 27 static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = { 28 [NCSI_ATTR_IFINDEX] = { .type = NLA_U32 }, 29 [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED }, 30 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 }, 31 [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 }, 32 }; 33 34 static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) 35 { 36 struct ncsi_dev_priv *ndp; 37 struct net_device *dev; 38 struct ncsi_dev *nd; 39 struct ncsi_dev; 40 41 if (!net) 42 return NULL; 43 44 dev = dev_get_by_index(net, ifindex); 45 if (!dev) { 46 pr_err("NCSI netlink: No device for ifindex %u\n", ifindex); 47 return NULL; 48 } 49 50 nd = ncsi_find_dev(dev); 51 ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL; 52 53 dev_put(dev); 54 return ndp; 55 } 56 57 static int ncsi_write_channel_info(struct sk_buff *skb, 58 struct ncsi_dev_priv *ndp, 59 struct ncsi_channel *nc) 60 { 61 struct ncsi_channel_vlan_filter *ncf; 62 struct ncsi_channel_mode *m; 63 struct nlattr *vid_nest; 64 int i; 65 66 nla_put_u32(skb, NCSI_CHANNEL_ATTR_ID, nc->id); 67 m = &nc->modes[NCSI_MODE_LINK]; 68 nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]); 69 if (nc->state == NCSI_CHANNEL_ACTIVE) 70 nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE); 71 if (ndp->force_channel == nc) 72 nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED); 73 74 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version); 75 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2); 76 nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name); 77 78 vid_nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR_VLAN_LIST); 79 if (!vid_nest) 80 return -ENOMEM; 81 ncf = &nc->vlan_filter; 82 i = -1; 83 while ((i = find_next_bit((void *)&ncf->bitmap, ncf->n_vids, 84 i + 1)) < ncf->n_vids) { 85 if (ncf->vids[i]) 86 nla_put_u16(skb, NCSI_CHANNEL_ATTR_VLAN_ID, 87 ncf->vids[i]); 88 } 89 nla_nest_end(skb, vid_nest); 90 91 return 0; 92 } 93 94 static int ncsi_write_package_info(struct sk_buff *skb, 95 struct ncsi_dev_priv *ndp, unsigned int id) 96 { 97 struct nlattr *pnest, *cnest, *nest; 98 struct ncsi_package *np; 99 struct ncsi_channel *nc; 100 bool found; 101 int rc; 102 103 if (id > ndp->package_num) { 104 netdev_info(ndp->ndev.dev, "NCSI: No package with id %u\n", id); 105 return -ENODEV; 106 } 107 108 found = false; 109 NCSI_FOR_EACH_PACKAGE(ndp, np) { 110 if (np->id != id) 111 continue; 112 pnest = nla_nest_start(skb, NCSI_PKG_ATTR); 113 if (!pnest) 114 return -ENOMEM; 115 nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id); 116 if (ndp->force_package == np) 117 nla_put_flag(skb, NCSI_PKG_ATTR_FORCED); 118 cnest = nla_nest_start(skb, NCSI_PKG_ATTR_CHANNEL_LIST); 119 if (!cnest) { 120 nla_nest_cancel(skb, pnest); 121 return -ENOMEM; 122 } 123 NCSI_FOR_EACH_CHANNEL(np, nc) { 124 nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR); 125 if (!nest) { 126 nla_nest_cancel(skb, cnest); 127 nla_nest_cancel(skb, pnest); 128 return -ENOMEM; 129 } 130 rc = ncsi_write_channel_info(skb, ndp, nc); 131 if (rc) { 132 nla_nest_cancel(skb, nest); 133 nla_nest_cancel(skb, cnest); 134 nla_nest_cancel(skb, pnest); 135 return rc; 136 } 137 nla_nest_end(skb, nest); 138 } 139 nla_nest_end(skb, cnest); 140 nla_nest_end(skb, pnest); 141 found = true; 142 } 143 144 if (!found) 145 return -ENODEV; 146 147 return 0; 148 } 149 150 static int ncsi_pkg_info_nl(struct sk_buff *msg, struct genl_info *info) 151 { 152 struct ncsi_dev_priv *ndp; 153 unsigned int package_id; 154 struct sk_buff *skb; 155 struct nlattr *attr; 156 void *hdr; 157 int rc; 158 159 if (!info || !info->attrs) 160 return -EINVAL; 161 162 if (!info->attrs[NCSI_ATTR_IFINDEX]) 163 return -EINVAL; 164 165 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 166 return -EINVAL; 167 168 ndp = ndp_from_ifindex(genl_info_net(info), 169 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 170 if (!ndp) 171 return -ENODEV; 172 173 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 174 if (!skb) 175 return -ENOMEM; 176 177 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 178 &ncsi_genl_family, 0, NCSI_CMD_PKG_INFO); 179 if (!hdr) { 180 kfree_skb(skb); 181 return -EMSGSIZE; 182 } 183 184 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 185 186 attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST); 187 if (!attr) { 188 kfree_skb(skb); 189 return -EMSGSIZE; 190 } 191 rc = ncsi_write_package_info(skb, ndp, package_id); 192 193 if (rc) { 194 nla_nest_cancel(skb, attr); 195 goto err; 196 } 197 198 nla_nest_end(skb, attr); 199 200 genlmsg_end(skb, hdr); 201 return genlmsg_reply(skb, info); 202 203 err: 204 genlmsg_cancel(skb, hdr); 205 kfree_skb(skb); 206 return rc; 207 } 208 209 static int ncsi_pkg_info_all_nl(struct sk_buff *skb, 210 struct netlink_callback *cb) 211 { 212 struct nlattr *attrs[NCSI_ATTR_MAX]; 213 struct ncsi_package *np, *package; 214 struct ncsi_dev_priv *ndp; 215 unsigned int package_id; 216 struct nlattr *attr; 217 void *hdr; 218 int rc; 219 220 rc = genlmsg_parse(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX, 221 ncsi_genl_policy, NULL); 222 if (rc) 223 return rc; 224 225 if (!attrs[NCSI_ATTR_IFINDEX]) 226 return -EINVAL; 227 228 ndp = ndp_from_ifindex(get_net(sock_net(skb->sk)), 229 nla_get_u32(attrs[NCSI_ATTR_IFINDEX])); 230 231 if (!ndp) 232 return -ENODEV; 233 234 package_id = cb->args[0]; 235 package = NULL; 236 NCSI_FOR_EACH_PACKAGE(ndp, np) 237 if (np->id == package_id) 238 package = np; 239 240 if (!package) 241 return 0; /* done */ 242 243 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 244 &ncsi_genl_family, 0, NCSI_CMD_PKG_INFO); 245 if (!hdr) { 246 rc = -EMSGSIZE; 247 goto err; 248 } 249 250 attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST); 251 rc = ncsi_write_package_info(skb, ndp, package->id); 252 if (rc) { 253 nla_nest_cancel(skb, attr); 254 goto err; 255 } 256 257 nla_nest_end(skb, attr); 258 genlmsg_end(skb, hdr); 259 260 cb->args[0] = package_id + 1; 261 262 return skb->len; 263 err: 264 genlmsg_cancel(skb, hdr); 265 return rc; 266 } 267 268 static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info) 269 { 270 struct ncsi_package *np, *package; 271 struct ncsi_channel *nc, *channel; 272 u32 package_id, channel_id; 273 struct ncsi_dev_priv *ndp; 274 unsigned long flags; 275 276 if (!info || !info->attrs) 277 return -EINVAL; 278 279 if (!info->attrs[NCSI_ATTR_IFINDEX]) 280 return -EINVAL; 281 282 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 283 return -EINVAL; 284 285 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 286 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 287 if (!ndp) 288 return -ENODEV; 289 290 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 291 package = NULL; 292 293 spin_lock_irqsave(&ndp->lock, flags); 294 295 NCSI_FOR_EACH_PACKAGE(ndp, np) 296 if (np->id == package_id) 297 package = np; 298 if (!package) { 299 /* The user has set a package that does not exist */ 300 spin_unlock_irqrestore(&ndp->lock, flags); 301 return -ERANGE; 302 } 303 304 channel = NULL; 305 if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) { 306 /* Allow any channel */ 307 channel_id = NCSI_RESERVED_CHANNEL; 308 } else { 309 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); 310 NCSI_FOR_EACH_CHANNEL(package, nc) 311 if (nc->id == channel_id) 312 channel = nc; 313 } 314 315 if (channel_id != NCSI_RESERVED_CHANNEL && !channel) { 316 /* The user has set a channel that does not exist on this 317 * package 318 */ 319 spin_unlock_irqrestore(&ndp->lock, flags); 320 netdev_info(ndp->ndev.dev, "NCSI: Channel %u does not exist!\n", 321 channel_id); 322 return -ERANGE; 323 } 324 325 ndp->force_package = package; 326 ndp->force_channel = channel; 327 spin_unlock_irqrestore(&ndp->lock, flags); 328 329 netdev_info(ndp->ndev.dev, "Set package 0x%x, channel 0x%x%s as preferred\n", 330 package_id, channel_id, 331 channel_id == NCSI_RESERVED_CHANNEL ? " (any)" : ""); 332 333 /* Bounce the NCSI channel to set changes */ 334 ncsi_stop_dev(&ndp->ndev); 335 ncsi_start_dev(&ndp->ndev); 336 337 return 0; 338 } 339 340 static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info) 341 { 342 struct ncsi_dev_priv *ndp; 343 unsigned long flags; 344 345 if (!info || !info->attrs) 346 return -EINVAL; 347 348 if (!info->attrs[NCSI_ATTR_IFINDEX]) 349 return -EINVAL; 350 351 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 352 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 353 if (!ndp) 354 return -ENODEV; 355 356 /* Clear any override */ 357 spin_lock_irqsave(&ndp->lock, flags); 358 ndp->force_package = NULL; 359 ndp->force_channel = NULL; 360 spin_unlock_irqrestore(&ndp->lock, flags); 361 netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n"); 362 363 /* Bounce the NCSI channel to set changes */ 364 ncsi_stop_dev(&ndp->ndev); 365 ncsi_start_dev(&ndp->ndev); 366 367 return 0; 368 } 369 370 static const struct genl_ops ncsi_ops[] = { 371 { 372 .cmd = NCSI_CMD_PKG_INFO, 373 .policy = ncsi_genl_policy, 374 .doit = ncsi_pkg_info_nl, 375 .dumpit = ncsi_pkg_info_all_nl, 376 .flags = 0, 377 }, 378 { 379 .cmd = NCSI_CMD_SET_INTERFACE, 380 .policy = ncsi_genl_policy, 381 .doit = ncsi_set_interface_nl, 382 .flags = GENL_ADMIN_PERM, 383 }, 384 { 385 .cmd = NCSI_CMD_CLEAR_INTERFACE, 386 .policy = ncsi_genl_policy, 387 .doit = ncsi_clear_interface_nl, 388 .flags = GENL_ADMIN_PERM, 389 }, 390 }; 391 392 static struct genl_family ncsi_genl_family __ro_after_init = { 393 .name = "NCSI", 394 .version = 0, 395 .maxattr = NCSI_ATTR_MAX, 396 .module = THIS_MODULE, 397 .ops = ncsi_ops, 398 .n_ops = ARRAY_SIZE(ncsi_ops), 399 }; 400 401 int ncsi_init_netlink(struct net_device *dev) 402 { 403 int rc; 404 405 rc = genl_register_family(&ncsi_genl_family); 406 if (rc) 407 netdev_err(dev, "ncsi: failed to register netlink family\n"); 408 409 return rc; 410 } 411 412 int ncsi_unregister_netlink(struct net_device *dev) 413 { 414 int rc; 415 416 rc = genl_unregister_family(&ncsi_genl_family); 417 if (rc) 418 netdev_err(dev, "ncsi: failed to unregister netlink family\n"); 419 420 return rc; 421 } 422