| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. |
|---|
| 2 | 3 | * |
|---|
| 3 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 4 | | - * it under the terms of the GNU General Public License version 2 and |
|---|
| 5 | | - * only version 2 as published by the Free Software Foundation. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 8 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 9 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 10 | | - * GNU General Public License for more details. |
|---|
| 11 | | - * |
|---|
| 12 | 4 | * RMNET configuration engine |
|---|
| 13 | | - * |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <net/sock.h> |
|---|
| .. | .. |
|---|
| 35 | 26 | } |
|---|
| 36 | 27 | |
|---|
| 37 | 28 | /* Needs rtnl lock */ |
|---|
| 38 | | -static struct rmnet_port* |
|---|
| 29 | +struct rmnet_port* |
|---|
| 39 | 30 | rmnet_get_port_rtnl(const struct net_device *real_dev) |
|---|
| 40 | 31 | { |
|---|
| 41 | 32 | return rtnl_dereference(real_dev->rx_handler_data); |
|---|
| .. | .. |
|---|
| 74 | 65 | return 0; |
|---|
| 75 | 66 | } |
|---|
| 76 | 67 | |
|---|
| 77 | | - port = kzalloc(sizeof(*port), GFP_ATOMIC); |
|---|
| 68 | + port = kzalloc(sizeof(*port), GFP_KERNEL); |
|---|
| 78 | 69 | if (!port) |
|---|
| 79 | 70 | return -ENOMEM; |
|---|
| 80 | 71 | |
|---|
| .. | .. |
|---|
| 139 | 130 | } |
|---|
| 140 | 131 | |
|---|
| 141 | 132 | real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); |
|---|
| 142 | | - if (!real_dev || !dev) |
|---|
| 133 | + if (!real_dev) { |
|---|
| 134 | + NL_SET_ERR_MSG_MOD(extack, "link does not exist"); |
|---|
| 143 | 135 | return -ENODEV; |
|---|
| 136 | + } |
|---|
| 144 | 137 | |
|---|
| 145 | | - if (!data[IFLA_RMNET_MUX_ID]) |
|---|
| 146 | | - return -EINVAL; |
|---|
| 147 | | - |
|---|
| 148 | | - ep = kzalloc(sizeof(*ep), GFP_ATOMIC); |
|---|
| 138 | + ep = kzalloc(sizeof(*ep), GFP_KERNEL); |
|---|
| 149 | 139 | if (!ep) |
|---|
| 150 | 140 | return -ENOMEM; |
|---|
| 151 | 141 | |
|---|
| .. | .. |
|---|
| 156 | 146 | goto err0; |
|---|
| 157 | 147 | |
|---|
| 158 | 148 | port = rmnet_get_port_rtnl(real_dev); |
|---|
| 159 | | - err = rmnet_vnd_newlink(mux_id, dev, port, real_dev, ep); |
|---|
| 149 | + err = rmnet_vnd_newlink(mux_id, dev, port, real_dev, ep, extack); |
|---|
| 160 | 150 | if (err) |
|---|
| 161 | 151 | goto err1; |
|---|
| 162 | 152 | |
|---|
| .. | .. |
|---|
| 263 | 253 | netdev_dbg(real_dev, "Kernel unregister\n"); |
|---|
| 264 | 254 | rmnet_force_unassociate_device(real_dev); |
|---|
| 265 | 255 | break; |
|---|
| 266 | | - |
|---|
| 256 | + case NETDEV_CHANGEMTU: |
|---|
| 257 | + if (rmnet_vnd_validate_real_dev_mtu(real_dev)) |
|---|
| 258 | + return NOTIFY_BAD; |
|---|
| 259 | + break; |
|---|
| 267 | 260 | default: |
|---|
| 268 | 261 | break; |
|---|
| 269 | 262 | } |
|---|
| .. | .. |
|---|
| 280 | 273 | { |
|---|
| 281 | 274 | u16 mux_id; |
|---|
| 282 | 275 | |
|---|
| 283 | | - if (!data || !data[IFLA_RMNET_MUX_ID]) |
|---|
| 276 | + if (!data || !data[IFLA_RMNET_MUX_ID]) { |
|---|
| 277 | + NL_SET_ERR_MSG_MOD(extack, "MUX ID not specified"); |
|---|
| 284 | 278 | return -EINVAL; |
|---|
| 279 | + } |
|---|
| 285 | 280 | |
|---|
| 286 | 281 | mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]); |
|---|
| 287 | | - if (mux_id > (RMNET_MAX_LOGICAL_EP - 1)) |
|---|
| 282 | + if (mux_id > (RMNET_MAX_LOGICAL_EP - 1)) { |
|---|
| 283 | + NL_SET_ERR_MSG_MOD(extack, "invalid MUX ID"); |
|---|
| 288 | 284 | return -ERANGE; |
|---|
| 285 | + } |
|---|
| 289 | 286 | |
|---|
| 290 | 287 | return 0; |
|---|
| 291 | 288 | } |
|---|
| .. | .. |
|---|
| 335 | 332 | |
|---|
| 336 | 333 | if (data[IFLA_RMNET_FLAGS]) { |
|---|
| 337 | 334 | struct ifla_rmnet_flags *flags; |
|---|
| 335 | + u32 old_data_format; |
|---|
| 338 | 336 | |
|---|
| 337 | + old_data_format = port->data_format; |
|---|
| 339 | 338 | flags = nla_data(data[IFLA_RMNET_FLAGS]); |
|---|
| 340 | 339 | port->data_format = flags->flags & flags->mask; |
|---|
| 340 | + |
|---|
| 341 | + if (rmnet_vnd_update_dev_mtu(port, real_dev)) { |
|---|
| 342 | + port->data_format = old_data_format; |
|---|
| 343 | + NL_SET_ERR_MSG_MOD(extack, "Invalid MTU on real dev"); |
|---|
| 344 | + return -EINVAL; |
|---|
| 345 | + } |
|---|
| 341 | 346 | } |
|---|
| 342 | 347 | |
|---|
| 343 | 348 | return 0; |
|---|
| .. | .. |
|---|
| 430 | 435 | /* If there is more than one rmnet dev attached, its probably being |
|---|
| 431 | 436 | * used for muxing. Skip the briding in that case |
|---|
| 432 | 437 | */ |
|---|
| 433 | | - if (port->nr_rmnet_devs > 1) |
|---|
| 438 | + if (port->nr_rmnet_devs > 1) { |
|---|
| 439 | + NL_SET_ERR_MSG_MOD(extack, "more than one rmnet dev attached"); |
|---|
| 434 | 440 | return -EINVAL; |
|---|
| 441 | + } |
|---|
| 435 | 442 | |
|---|
| 436 | | - if (rmnet_is_real_dev_registered(slave_dev)) |
|---|
| 443 | + if (port->rmnet_mode != RMNET_EPMODE_VND) { |
|---|
| 444 | + NL_SET_ERR_MSG_MOD(extack, "more than one bridge dev attached"); |
|---|
| 445 | + return -EINVAL; |
|---|
| 446 | + } |
|---|
| 447 | + |
|---|
| 448 | + if (rmnet_is_real_dev_registered(slave_dev)) { |
|---|
| 449 | + NL_SET_ERR_MSG_MOD(extack, |
|---|
| 450 | + "slave cannot be another rmnet dev"); |
|---|
| 451 | + |
|---|
| 437 | 452 | return -EBUSY; |
|---|
| 453 | + } |
|---|
| 438 | 454 | |
|---|
| 439 | 455 | err = rmnet_register_real_device(slave_dev, extack); |
|---|
| 440 | 456 | if (err) |
|---|
| .. | .. |
|---|
| 496 | 512 | |
|---|
| 497 | 513 | module_init(rmnet_init) |
|---|
| 498 | 514 | module_exit(rmnet_exit) |
|---|
| 515 | +MODULE_ALIAS_RTNL_LINK("rmnet"); |
|---|
| 499 | 516 | MODULE_LICENSE("GPL v2"); |
|---|