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 kfree_skb(skb); 205 return rc; 206 } 207 208 static int ncsi_pkg_info_all_nl(struct sk_buff *skb, 209 struct netlink_callback *cb) 210 { 211 struct nlattr *attrs[NCSI_ATTR_MAX + 1]; 212 struct ncsi_package *np, *package; 213 struct ncsi_dev_priv *ndp; 214 unsigned int package_id; 215 struct nlattr *attr; 216 void *hdr; 217 int rc; 218 219 rc = genlmsg_parse(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX, 220 ncsi_genl_policy, NULL); 221 if (rc) 222 return rc; 223 224 if (!attrs[NCSI_ATTR_IFINDEX]) 225 return -EINVAL; 226 227 ndp = ndp_from_ifindex(get_net(sock_net(skb->sk)), 228 nla_get_u32(attrs[NCSI_ATTR_IFINDEX])); 229 230 if (!ndp) 231 return -ENODEV; 232 233 package_id = cb->args[0]; 234 package = NULL; 235 NCSI_FOR_EACH_PACKAGE(ndp, np) 236 if (np->id == package_id) 237 package = np; 238 239 if (!package) 240 return 0; /* done */ 241 242 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 243 &ncsi_genl_family, 0, NCSI_CMD_PKG_INFO); 244 if (!hdr) { 245 rc = -EMSGSIZE; 246 goto err; 247 } 248 249 attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST); 250 rc = ncsi_write_package_info(skb, ndp, package->id); 251 if (rc) { 252 nla_nest_cancel(skb, attr); 253 goto err; 254 } 255 256 nla_nest_end(skb, attr); 257 genlmsg_end(skb, hdr); 258 259 cb->args[0] = package_id + 1; 260 261 return skb->len; 262 err: 263 genlmsg_cancel(skb, hdr); 264 return rc; 265 } 266 267 static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info) 268 { 269 struct ncsi_package *np, *package; 270 struct ncsi_channel *nc, *channel; 271 u32 package_id, channel_id; 272 struct ncsi_dev_priv *ndp; 273 unsigned long flags; 274 275 if (!info || !info->attrs) 276 return -EINVAL; 277 278 if (!info->attrs[NCSI_ATTR_IFINDEX]) 279 return -EINVAL; 280 281 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 282 return -EINVAL; 283 284 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 285 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 286 if (!ndp) 287 return -ENODEV; 288 289 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 290 package = NULL; 291 292 spin_lock_irqsave(&ndp->lock, flags); 293 294 NCSI_FOR_EACH_PACKAGE(ndp, np) 295 if (np->id == package_id) 296 package = np; 297 if (!package) { 298 /* The user has set a package that does not exist */ 299 spin_unlock_irqrestore(&ndp->lock, flags); 300 return -ERANGE; 301 } 302 303 channel = NULL; 304 if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) { 305 /* Allow any channel */ 306 channel_id = NCSI_RESERVED_CHANNEL; 307 } else { 308 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); 309 NCSI_FOR_EACH_CHANNEL(package, nc) 310 if (nc->id == channel_id) 311 channel = nc; 312 } 313 314 if (channel_id != NCSI_RESERVED_CHANNEL && !channel) { 315 /* The user has set a channel that does not exist on this 316 * package 317 */ 318 spin_unlock_irqrestore(&ndp->lock, flags); 319 netdev_info(ndp->ndev.dev, "NCSI: Channel %u does not exist!\n", 320 channel_id); 321 return -ERANGE; 322 } 323 324 ndp->force_package = package; 325 ndp->force_channel = channel; 326 spin_unlock_irqrestore(&ndp->lock, flags); 327 328 netdev_info(ndp->ndev.dev, "Set package 0x%x, channel 0x%x%s as preferred\n", 329 package_id, channel_id, 330 channel_id == NCSI_RESERVED_CHANNEL ? " (any)" : ""); 331 332 /* Bounce the NCSI channel to set changes */ 333 ncsi_stop_dev(&ndp->ndev); 334 ncsi_start_dev(&ndp->ndev); 335 336 return 0; 337 } 338 339 static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info) 340 { 341 struct ncsi_dev_priv *ndp; 342 unsigned long flags; 343 344 if (!info || !info->attrs) 345 return -EINVAL; 346 347 if (!info->attrs[NCSI_ATTR_IFINDEX]) 348 return -EINVAL; 349 350 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 351 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 352 if (!ndp) 353 return -ENODEV; 354 355 /* Clear any override */ 356 spin_lock_irqsave(&ndp->lock, flags); 357 ndp->force_package = NULL; 358 ndp->force_channel = NULL; 359 spin_unlock_irqrestore(&ndp->lock, flags); 360 netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n"); 361 362 /* Bounce the NCSI channel to set changes */ 363 ncsi_stop_dev(&ndp->ndev); 364 ncsi_start_dev(&ndp->ndev); 365 366 return 0; 367 } 368 369 static const struct genl_ops ncsi_ops[] = { 370 { 371 .cmd = NCSI_CMD_PKG_INFO, 372 .policy = ncsi_genl_policy, 373 .doit = ncsi_pkg_info_nl, 374 .dumpit = ncsi_pkg_info_all_nl, 375 .flags = 0, 376 }, 377 { 378 .cmd = NCSI_CMD_SET_INTERFACE, 379 .policy = ncsi_genl_policy, 380 .doit = ncsi_set_interface_nl, 381 .flags = GENL_ADMIN_PERM, 382 }, 383 { 384 .cmd = NCSI_CMD_CLEAR_INTERFACE, 385 .policy = ncsi_genl_policy, 386 .doit = ncsi_clear_interface_nl, 387 .flags = GENL_ADMIN_PERM, 388 }, 389 }; 390 391 static struct genl_family ncsi_genl_family __ro_after_init = { 392 .name = "NCSI", 393 .version = 0, 394 .maxattr = NCSI_ATTR_MAX, 395 .module = THIS_MODULE, 396 .ops = ncsi_ops, 397 .n_ops = ARRAY_SIZE(ncsi_ops), 398 }; 399 400 int ncsi_init_netlink(struct net_device *dev) 401 { 402 int rc; 403 404 rc = genl_register_family(&ncsi_genl_family); 405 if (rc) 406 netdev_err(dev, "ncsi: failed to register netlink family\n"); 407 408 return rc; 409 } 410 411 int ncsi_unregister_netlink(struct net_device *dev) 412 { 413 int rc; 414 415 rc = genl_unregister_family(&ncsi_genl_family); 416 if (rc) 417 netdev_err(dev, "ncsi: failed to unregister netlink family\n"); 418 419 return rc; 420 } 421