1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (C) 2010-2020 B.A.T.M.A.N. contributors: 3 * 4 * Marek Lindner 5 */ 6 7#include "sysfs.h" 8#include "main.h" 9 10#include <asm/current.h> 11#include <linux/atomic.h> 12#include <linux/compiler.h> 13#include <linux/device.h> 14#include <linux/errno.h> 15#include <linux/gfp.h> 16#include <linux/if.h> 17#include <linux/if_vlan.h> 18#include <linux/kernel.h> 19#include <linux/kobject.h> 20#include <linux/kref.h> 21#include <linux/limits.h> 22#include <linux/netdevice.h> 23#include <linux/printk.h> 24#include <linux/rculist.h> 25#include <linux/rcupdate.h> 26#include <linux/rtnetlink.h> 27#include <linux/sched.h> 28#include <linux/slab.h> 29#include <linux/stddef.h> 30#include <linux/string.h> 31#include <linux/stringify.h> 32#include <linux/workqueue.h> 33#include <uapi/linux/batadv_packet.h> 34#include <uapi/linux/batman_adv.h> 35 36#include "bridge_loop_avoidance.h" 37#include "distributed-arp-table.h" 38#include "gateway_client.h" 39#include "gateway_common.h" 40#include "hard-interface.h" 41#include "log.h" 42#include "netlink.h" 43#include "network-coding.h" 44#include "soft-interface.h" 45 46/** 47 * batadv_sysfs_deprecated() - Log use of deprecated batadv sysfs access 48 * @attr: attribute which was accessed 49 */ 50static void batadv_sysfs_deprecated(struct attribute *attr) 51{ 52 pr_warn_ratelimited(DEPRECATED "%s (pid %d) Use of sysfs file \"%s\".\nUse batadv genl family instead", 53 current->comm, task_pid_nr(current), attr->name); 54} 55 56static struct net_device *batadv_kobj_to_netdev(struct kobject *obj) 57{ 58 struct device *dev = container_of(obj->parent, struct device, kobj); 59 60 return to_net_dev(dev); 61} 62 63static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj) 64{ 65 struct net_device *net_dev = batadv_kobj_to_netdev(obj); 66 67 return netdev_priv(net_dev); 68} 69 70/** 71 * batadv_vlan_kobj_to_batpriv() - convert a vlan kobj in the associated batpriv 72 * @obj: kobject to covert 73 * 74 * Return: the associated batadv_priv struct. 75 */ 76static struct batadv_priv *batadv_vlan_kobj_to_batpriv(struct kobject *obj) 77{ 78 /* VLAN specific attributes are located in the root sysfs folder if they 79 * refer to the untagged VLAN.. 80 */ 81 if (!strcmp(BATADV_SYSFS_IF_MESH_SUBDIR, obj->name)) 82 return batadv_kobj_to_batpriv(obj); 83 84 /* ..while the attributes for the tagged vlans are located in 85 * the in the corresponding "vlan%VID" subfolder 86 */ 87 return batadv_kobj_to_batpriv(obj->parent); 88} 89 90/** 91 * batadv_kobj_to_vlan() - convert a kobj in the associated softif_vlan struct 92 * @bat_priv: the bat priv with all the soft interface information 93 * @obj: kobject to covert 94 * 95 * Return: the associated softif_vlan struct if found, NULL otherwise. 96 */ 97static struct batadv_softif_vlan * 98batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj) 99{ 100 struct batadv_softif_vlan *vlan_tmp, *vlan = NULL; 101 102 rcu_read_lock(); 103 hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) { 104 if (vlan_tmp->kobj != obj) 105 continue; 106 107 if (!kref_get_unless_zero(&vlan_tmp->refcount)) 108 continue; 109 110 vlan = vlan_tmp; 111 break; 112 } 113 rcu_read_unlock(); 114 115 return vlan; 116} 117 118/* Use this, if you have customized show and store functions for vlan attrs */ 119#define BATADV_ATTR_VLAN(_name, _mode, _show, _store) \ 120struct batadv_attribute batadv_attr_vlan_##_name = { \ 121 .attr = {.name = __stringify(_name), \ 122 .mode = _mode }, \ 123 .show = _show, \ 124 .store = _store, \ 125} 126 127/* Use this, if you have customized show and store functions */ 128#define BATADV_ATTR(_name, _mode, _show, _store) \ 129struct batadv_attribute batadv_attr_##_name = { \ 130 .attr = {.name = __stringify(_name), \ 131 .mode = _mode }, \ 132 .show = _show, \ 133 .store = _store, \ 134} 135 136#define BATADV_ATTR_SIF_STORE_BOOL(_name, _post_func) \ 137ssize_t batadv_store_##_name(struct kobject *kobj, \ 138 struct attribute *attr, char *buff, \ 139 size_t count) \ 140{ \ 141 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ 142 struct batadv_priv *bat_priv = netdev_priv(net_dev); \ 143 ssize_t length; \ 144 \ 145 batadv_sysfs_deprecated(attr); \ 146 length = __batadv_store_bool_attr(buff, count, _post_func, attr,\ 147 &bat_priv->_name, net_dev); \ 148 \ 149 batadv_netlink_notify_mesh(bat_priv); \ 150 \ 151 return length; \ 152} 153 154#define BATADV_ATTR_SIF_SHOW_BOOL(_name) \ 155ssize_t batadv_show_##_name(struct kobject *kobj, \ 156 struct attribute *attr, char *buff) \ 157{ \ 158 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); \ 159 \ 160 batadv_sysfs_deprecated(attr); \ 161 return sprintf(buff, "%s\n", \ 162 atomic_read(&bat_priv->_name) == 0 ? \ 163 "disabled" : "enabled"); \ 164} \ 165 166/* Use this, if you are going to turn a [name] in the soft-interface 167 * (bat_priv) on or off 168 */ 169#define BATADV_ATTR_SIF_BOOL(_name, _mode, _post_func) \ 170 static BATADV_ATTR_SIF_STORE_BOOL(_name, _post_func) \ 171 static BATADV_ATTR_SIF_SHOW_BOOL(_name) \ 172 static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ 173 batadv_store_##_name) 174 175#define BATADV_ATTR_SIF_STORE_UINT(_name, _var, _min, _max, _post_func) \ 176ssize_t batadv_store_##_name(struct kobject *kobj, \ 177 struct attribute *attr, char *buff, \ 178 size_t count) \ 179{ \ 180 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ 181 struct batadv_priv *bat_priv = netdev_priv(net_dev); \ 182 ssize_t length; \ 183 \ 184 batadv_sysfs_deprecated(attr); \ 185 length = __batadv_store_uint_attr(buff, count, _min, _max, \ 186 _post_func, attr, \ 187 &bat_priv->_var, net_dev, \ 188 NULL); \ 189 \ 190 batadv_netlink_notify_mesh(bat_priv); \ 191 \ 192 return length; \ 193} 194 195#define BATADV_ATTR_SIF_SHOW_UINT(_name, _var) \ 196ssize_t batadv_show_##_name(struct kobject *kobj, \ 197 struct attribute *attr, char *buff) \ 198{ \ 199 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); \ 200 \ 201 batadv_sysfs_deprecated(attr); \ 202 return sprintf(buff, "%i\n", atomic_read(&bat_priv->_var)); \ 203} \ 204 205/* Use this, if you are going to set [name] in the soft-interface 206 * (bat_priv) to an unsigned integer value 207 */ 208#define BATADV_ATTR_SIF_UINT(_name, _var, _mode, _min, _max, _post_func)\ 209 static BATADV_ATTR_SIF_STORE_UINT(_name, _var, _min, _max, _post_func)\ 210 static BATADV_ATTR_SIF_SHOW_UINT(_name, _var) \ 211 static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ 212 batadv_store_##_name) 213 214#define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \ 215ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \ 216 struct attribute *attr, char *buff, \ 217 size_t count) \ 218{ \ 219 struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\ 220 struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \ 221 kobj); \ 222 size_t res = __batadv_store_bool_attr(buff, count, _post_func, \ 223 attr, &vlan->_name, \ 224 bat_priv->soft_iface); \ 225 \ 226 batadv_sysfs_deprecated(attr); \ 227 if (vlan->vid) \ 228 batadv_netlink_notify_vlan(bat_priv, vlan); \ 229 else \ 230 batadv_netlink_notify_mesh(bat_priv); \ 231 \ 232 batadv_softif_vlan_put(vlan); \ 233 return res; \ 234} 235 236#define BATADV_ATTR_VLAN_SHOW_BOOL(_name) \ 237ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \ 238 struct attribute *attr, char *buff) \ 239{ \ 240 struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\ 241 struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \ 242 kobj); \ 243 size_t res = sprintf(buff, "%s\n", \ 244 atomic_read(&vlan->_name) == 0 ? \ 245 "disabled" : "enabled"); \ 246 \ 247 batadv_sysfs_deprecated(attr); \ 248 batadv_softif_vlan_put(vlan); \ 249 return res; \ 250} 251 252/* Use this, if you are going to turn a [name] in the vlan struct on or off */ 253#define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func) \ 254 static BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \ 255 static BATADV_ATTR_VLAN_SHOW_BOOL(_name) \ 256 static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \ 257 batadv_store_vlan_##_name) 258 259#define BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min, _max, _post_func) \ 260ssize_t batadv_store_##_name(struct kobject *kobj, \ 261 struct attribute *attr, char *buff, \ 262 size_t count) \ 263{ \ 264 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ 265 struct batadv_hard_iface *hard_iface; \ 266 struct batadv_priv *bat_priv; \ 267 ssize_t length; \ 268 \ 269 batadv_sysfs_deprecated(attr); \ 270 hard_iface = batadv_hardif_get_by_netdev(net_dev); \ 271 if (!hard_iface) \ 272 return 0; \ 273 \ 274 length = __batadv_store_uint_attr(buff, count, _min, _max, \ 275 _post_func, attr, \ 276 &hard_iface->_var, \ 277 hard_iface->soft_iface, \ 278 net_dev); \ 279 \ 280 if (hard_iface->soft_iface) { \ 281 bat_priv = netdev_priv(hard_iface->soft_iface); \ 282 batadv_netlink_notify_hardif(bat_priv, hard_iface); \ 283 } \ 284 \ 285 batadv_hardif_put(hard_iface); \ 286 return length; \ 287} 288 289#define BATADV_ATTR_HIF_SHOW_UINT(_name, _var) \ 290ssize_t batadv_show_##_name(struct kobject *kobj, \ 291 struct attribute *attr, char *buff) \ 292{ \ 293 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ 294 struct batadv_hard_iface *hard_iface; \ 295 ssize_t length; \ 296 \ 297 batadv_sysfs_deprecated(attr); \ 298 hard_iface = batadv_hardif_get_by_netdev(net_dev); \ 299 if (!hard_iface) \ 300 return 0; \ 301 \ 302 length = sprintf(buff, "%i\n", atomic_read(&hard_iface->_var)); \ 303 \ 304 batadv_hardif_put(hard_iface); \ 305 return length; \ 306} 307 308/* Use this, if you are going to set [name] in hard_iface to an 309 * unsigned integer value 310 */ 311#define BATADV_ATTR_HIF_UINT(_name, _var, _mode, _min, _max, _post_func)\ 312 static BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min, \ 313 _max, _post_func) \ 314 static BATADV_ATTR_HIF_SHOW_UINT(_name, _var) \ 315 static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ 316 batadv_store_##_name) 317 318static int batadv_store_bool_attr(char *buff, size_t count, 319 struct net_device *net_dev, 320 const char *attr_name, atomic_t *attr, 321 bool *changed) 322{ 323 int enabled = -1; 324 325 *changed = false; 326 327 if (buff[count - 1] == '\n') 328 buff[count - 1] = '\0'; 329 330 if ((strncmp(buff, "1", 2) == 0) || 331 (strncmp(buff, "enable", 7) == 0) || 332 (strncmp(buff, "enabled", 8) == 0)) 333 enabled = 1; 334 335 if ((strncmp(buff, "0", 2) == 0) || 336 (strncmp(buff, "disable", 8) == 0) || 337 (strncmp(buff, "disabled", 9) == 0)) 338 enabled = 0; 339 340 if (enabled < 0) { 341 batadv_info(net_dev, "%s: Invalid parameter received: %s\n", 342 attr_name, buff); 343 return -EINVAL; 344 } 345 346 if (atomic_read(attr) == enabled) 347 return count; 348 349 batadv_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, 350 atomic_read(attr) == 1 ? "enabled" : "disabled", 351 enabled == 1 ? "enabled" : "disabled"); 352 353 *changed = true; 354 355 atomic_set(attr, (unsigned int)enabled); 356 return count; 357} 358 359static inline ssize_t 360__batadv_store_bool_attr(char *buff, size_t count, 361 void (*post_func)(struct net_device *), 362 struct attribute *attr, 363 atomic_t *attr_store, struct net_device *net_dev) 364{ 365 bool changed; 366 int ret; 367 368 ret = batadv_store_bool_attr(buff, count, net_dev, attr->name, 369 attr_store, &changed); 370 if (post_func && changed) 371 post_func(net_dev); 372 373 return ret; 374} 375 376static int batadv_store_uint_attr(const char *buff, size_t count, 377 struct net_device *net_dev, 378 struct net_device *slave_dev, 379 const char *attr_name, 380 unsigned int min, unsigned int max, 381 atomic_t *attr) 382{ 383 char ifname[IFNAMSIZ + 3] = ""; 384 unsigned long uint_val; 385 int ret; 386 387 ret = kstrtoul(buff, 10, &uint_val); 388 if (ret) { 389 batadv_info(net_dev, "%s: Invalid parameter received: %s\n", 390 attr_name, buff); 391 return -EINVAL; 392 } 393 394 if (uint_val < min) { 395 batadv_info(net_dev, "%s: Value is too small: %lu min: %u\n", 396 attr_name, uint_val, min); 397 return -EINVAL; 398 } 399 400 if (uint_val > max) { 401 batadv_info(net_dev, "%s: Value is too big: %lu max: %u\n", 402 attr_name, uint_val, max); 403 return -EINVAL; 404 } 405 406 if (atomic_read(attr) == uint_val) 407 return count; 408 409 if (slave_dev) 410 snprintf(ifname, sizeof(ifname), "%s: ", slave_dev->name); 411 412 batadv_info(net_dev, "%s: %sChanging from: %i to: %lu\n", 413 attr_name, ifname, atomic_read(attr), uint_val); 414 415 atomic_set(attr, uint_val); 416 return count; 417} 418 419static ssize_t __batadv_store_uint_attr(const char *buff, size_t count, 420 int min, int max, 421 void (*post_func)(struct net_device *), 422 const struct attribute *attr, 423 atomic_t *attr_store, 424 struct net_device *net_dev, 425 struct net_device *slave_dev) 426{ 427 int ret; 428 429 ret = batadv_store_uint_attr(buff, count, net_dev, slave_dev, 430 attr->name, min, max, attr_store); 431 if (post_func && ret) 432 post_func(net_dev); 433 434 return ret; 435} 436 437static ssize_t batadv_show_bat_algo(struct kobject *kobj, 438 struct attribute *attr, char *buff) 439{ 440 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); 441 442 batadv_sysfs_deprecated(attr); 443 return sprintf(buff, "%s\n", bat_priv->algo_ops->name); 444} 445 446static void batadv_post_gw_reselect(struct net_device *net_dev) 447{ 448 struct batadv_priv *bat_priv = netdev_priv(net_dev); 449 450 batadv_gw_reselect(bat_priv); 451} 452 453static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr, 454 char *buff) 455{ 456 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); 457 int bytes_written; 458 459 batadv_sysfs_deprecated(attr); 460 461 /* GW mode is not available if the routing algorithm in use does not 462 * implement the GW API 463 */ 464 if (!bat_priv->algo_ops->gw.get_best_gw_node || 465 !bat_priv->algo_ops->gw.is_eligible) 466 return -ENOENT; 467 468 switch (atomic_read(&bat_priv->gw.mode)) { 469 case BATADV_GW_MODE_CLIENT: 470 bytes_written = sprintf(buff, "%s\n", 471 BATADV_GW_MODE_CLIENT_NAME); 472 break; 473 case BATADV_GW_MODE_SERVER: 474 bytes_written = sprintf(buff, "%s\n", 475 BATADV_GW_MODE_SERVER_NAME); 476 break; 477 default: 478 bytes_written = sprintf(buff, "%s\n", 479 BATADV_GW_MODE_OFF_NAME); 480 break; 481 } 482 483 return bytes_written; 484} 485 486static ssize_t batadv_store_gw_mode(struct kobject *kobj, 487 struct attribute *attr, char *buff, 488 size_t count) 489{ 490 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); 491 struct batadv_priv *bat_priv = netdev_priv(net_dev); 492 char *curr_gw_mode_str; 493 int gw_mode_tmp = -1; 494 495 batadv_sysfs_deprecated(attr); 496 497 /* toggling GW mode is allowed only if the routing algorithm in use 498 * provides the GW API 499 */ 500 if (!bat_priv->algo_ops->gw.get_best_gw_node || 501 !bat_priv->algo_ops->gw.is_eligible) 502 return -EINVAL; 503 504 if (buff[count - 1] == '\n') 505 buff[count - 1] = '\0'; 506 507 if (strncmp(buff, BATADV_GW_MODE_OFF_NAME, 508 strlen(BATADV_GW_MODE_OFF_NAME)) == 0) 509 gw_mode_tmp = BATADV_GW_MODE_OFF; 510 511 if (strncmp(buff, BATADV_GW_MODE_CLIENT_NAME, 512 strlen(BATADV_GW_MODE_CLIENT_NAME)) == 0) 513 gw_mode_tmp = BATADV_GW_MODE_CLIENT; 514 515 if (strncmp(buff, BATADV_GW_MODE_SERVER_NAME, 516 strlen(BATADV_GW_MODE_SERVER_NAME)) == 0) 517 gw_mode_tmp = BATADV_GW_MODE_SERVER; 518 519 if (gw_mode_tmp < 0) { 520 batadv_info(net_dev, 521 "Invalid parameter for 'gw mode' setting received: %s\n", 522 buff); 523 return -EINVAL; 524 } 525 526 if (atomic_read(&bat_priv->gw.mode) == gw_mode_tmp) 527 return count; 528 529 switch (atomic_read(&bat_priv->gw.mode)) { 530 case BATADV_GW_MODE_CLIENT: 531 curr_gw_mode_str = BATADV_GW_MODE_CLIENT_NAME; 532 break; 533 case BATADV_GW_MODE_SERVER: 534 curr_gw_mode_str = BATADV_GW_MODE_SERVER_NAME; 535 break; 536 default: 537 curr_gw_mode_str = BATADV_GW_MODE_OFF_NAME; 538 break; 539 } 540 541 batadv_info(net_dev, "Changing gw mode from: %s to: %s\n", 542 curr_gw_mode_str, buff); 543 544 /* Invoking batadv_gw_reselect() is not enough to really de-select the 545 * current GW. It will only instruct the gateway client code to perform 546 * a re-election the next time that this is needed. 547 * 548 * When gw client mode is being switched off the current GW must be 549 * de-selected explicitly otherwise no GW_ADD uevent is thrown on 550 * client mode re-activation. This is operation is performed in 551 * batadv_gw_check_client_stop(). 552 */ 553 batadv_gw_reselect(bat_priv); 554 /* always call batadv_gw_check_client_stop() before changing the gateway 555 * state 556 */ 557 batadv_gw_check_client_stop(bat_priv); 558 atomic_set(&bat_priv->gw.mode, (unsigned int)gw_mode_tmp); 559 batadv_gw_tvlv_container_update(bat_priv); 560 561 batadv_netlink_notify_mesh(bat_priv); 562 563 return count; 564} 565 566static ssize_t batadv_show_gw_sel_class(struct kobject *kobj, 567 struct attribute *attr, char *buff) 568{ 569 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); 570 571 batadv_sysfs_deprecated(attr); 572 573 /* GW selection class is not available if the routing algorithm in use 574 * does not implement the GW API 575 */ 576 if (!bat_priv->algo_ops->gw.get_best_gw_node || 577 !bat_priv->algo_ops->gw.is_eligible) 578 return -ENOENT; 579 580 if (bat_priv->algo_ops->gw.show_sel_class) 581 return bat_priv->algo_ops->gw.show_sel_class(bat_priv, buff); 582 583 return sprintf(buff, "%i\n", atomic_read(&bat_priv->gw.sel_class)); 584} 585 586static ssize_t batadv_store_gw_sel_class(struct kobject *kobj, 587 struct attribute *attr, char *buff, 588 size_t count) 589{ 590 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); 591 ssize_t length; 592 593 batadv_sysfs_deprecated(attr); 594 595 /* setting the GW selection class is allowed only if the routing 596 * algorithm in use implements the GW API 597 */ 598 if (!bat_priv->algo_ops->gw.get_best_gw_node || 599 !bat_priv->algo_ops->gw.is_eligible) 600 return -EINVAL; 601 602 if (buff[count - 1] == '\n') 603 buff[count - 1] = '\0'; 604 605 if (bat_priv->algo_ops->gw.store_sel_class) 606 return bat_priv->algo_ops->gw.store_sel_class(bat_priv, buff, 607 count); 608 609 length = __batadv_store_uint_attr(buff, count, 1, BATADV_TQ_MAX_VALUE, 610 batadv_post_gw_reselect, attr, 611 &bat_priv->gw.sel_class, 612 bat_priv->soft_iface, NULL); 613 614 batadv_netlink_notify_mesh(bat_priv); 615 616 return length; 617} 618 619static ssize_t batadv_show_gw_bwidth(struct kobject *kobj, 620 struct attribute *attr, char *buff) 621{ 622 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); 623 u32 down, up; 624 625 batadv_sysfs_deprecated(attr); 626 627 down = atomic_read(&bat_priv->gw.bandwidth_down); 628 up = atomic_read(&bat_priv->gw.bandwidth_up); 629 630 return sprintf(buff, "%u.%u/%u.%u MBit\n", down / 10, 631 down % 10, up / 10, up % 10); 632} 633 634static ssize_t batadv_store_gw_bwidth(struct kobject *kobj, 635 struct attribute *attr, char *buff, 636 size_t count) 637{ 638 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); 639 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); 640 ssize_t length; 641 642 batadv_sysfs_deprecated(attr); 643 644 if (buff[count - 1] == '\n') 645 buff[count - 1] = '\0'; 646 647 length = batadv_gw_bandwidth_set(net_dev, buff, count); 648 649 batadv_netlink_notify_mesh(bat_priv); 650 651 return length; 652} 653 654/** 655 * batadv_show_isolation_mark() - print the current isolation mark/mask 656 * @kobj: kobject representing the private mesh sysfs directory 657 * @attr: the batman-adv attribute the user is interacting with 658 * @buff: the buffer that will contain the data to send back to the user 659 * 660 * Return: the number of bytes written into 'buff' on success or a negative 661 * error code in case of failure 662 */ 663static ssize_t batadv_show_isolation_mark(struct kobject *kobj, 664 struct attribute *attr, char *buff) 665{ 666 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); 667 668 batadv_sysfs_deprecated(attr); 669 return sprintf(buff, "%#.8x/%#.8x\n", bat_priv->isolation_mark, 670 bat_priv->isolation_mark_mask); 671} 672 673/** 674 * batadv_store_isolation_mark() - parse and store the isolation mark/mask 675 * entered by the user 676 * @kobj: kobject representing the private mesh sysfs directory 677 * @attr: the batman-adv attribute the user is interacting with 678 * @buff: the buffer containing the user data 679 * @count: number of bytes in the buffer 680 * 681 * Return: 'count' on success or a negative error code in case of failure 682 */ 683static ssize_t batadv_store_isolation_mark(struct kobject *kobj, 684 struct attribute *attr, char *buff, 685 size_t count) 686{ 687 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); 688 struct batadv_priv *bat_priv = netdev_priv(net_dev); 689 u32 mark, mask; 690 char *mask_ptr; 691 692 batadv_sysfs_deprecated(attr); 693 694 /* parse the mask if it has been specified, otherwise assume the mask is 695 * the biggest possible 696 */ 697 mask = 0xFFFFFFFF; 698 mask_ptr = strchr(buff, '/'); 699 if (mask_ptr) { 700 *mask_ptr = '\0'; 701 mask_ptr++; 702 703 /* the mask must be entered in hex base as it is going to be a 704 * bitmask and not a prefix length 705 */ 706 if (kstrtou32(mask_ptr, 16, &mask) < 0) 707 return -EINVAL; 708 } 709 710 /* the mark can be entered in any base */ 711 if (kstrtou32(buff, 0, &mark) < 0) 712 return -EINVAL; 713 714 bat_priv->isolation_mark_mask = mask; 715 /* erase bits not covered by the mask */ 716 bat_priv->isolation_mark = mark & bat_priv->isolation_mark_mask; 717 718 batadv_info(net_dev, 719 "New skb mark for extended isolation: %#.8x/%#.8x\n", 720 bat_priv->isolation_mark, bat_priv->isolation_mark_mask); 721 722 batadv_netlink_notify_mesh(bat_priv); 723 724 return count; 725} 726 727BATADV_ATTR_SIF_BOOL(aggregated_ogms, 0644, NULL); 728BATADV_ATTR_SIF_BOOL(bonding, 0644, NULL); 729#ifdef CONFIG_BATMAN_ADV_BLA 730BATADV_ATTR_SIF_BOOL(bridge_loop_avoidance, 0644, batadv_bla_status_update); 731#endif 732#ifdef CONFIG_BATMAN_ADV_DAT 733BATADV_ATTR_SIF_BOOL(distributed_arp_table, 0644, batadv_dat_status_update); 734#endif 735BATADV_ATTR_SIF_BOOL(fragmentation, 0644, batadv_update_min_mtu); 736static BATADV_ATTR(routing_algo, 0444, batadv_show_bat_algo, NULL); 737static BATADV_ATTR(gw_mode, 0644, batadv_show_gw_mode, batadv_store_gw_mode); 738BATADV_ATTR_SIF_UINT(orig_interval, orig_interval, 0644, 2 * BATADV_JITTER, 739 INT_MAX, NULL); 740BATADV_ATTR_SIF_UINT(hop_penalty, hop_penalty, 0644, 0, BATADV_TQ_MAX_VALUE, 741 NULL); 742static BATADV_ATTR(gw_sel_class, 0644, batadv_show_gw_sel_class, 743 batadv_store_gw_sel_class); 744static BATADV_ATTR(gw_bandwidth, 0644, batadv_show_gw_bwidth, 745 batadv_store_gw_bwidth); 746#ifdef CONFIG_BATMAN_ADV_MCAST 747BATADV_ATTR_SIF_BOOL(multicast_mode, 0644, NULL); 748#endif 749#ifdef CONFIG_BATMAN_ADV_DEBUG 750BATADV_ATTR_SIF_UINT(log_level, log_level, 0644, 0, BATADV_DBG_ALL, NULL); 751#endif 752#ifdef CONFIG_BATMAN_ADV_NC 753BATADV_ATTR_SIF_BOOL(network_coding, 0644, batadv_nc_status_update); 754#endif 755static BATADV_ATTR(isolation_mark, 0644, batadv_show_isolation_mark, 756 batadv_store_isolation_mark); 757 758static struct batadv_attribute *batadv_mesh_attrs[] = { 759 &batadv_attr_aggregated_ogms, 760 &batadv_attr_bonding, 761#ifdef CONFIG_BATMAN_ADV_BLA 762 &batadv_attr_bridge_loop_avoidance, 763#endif 764#ifdef CONFIG_BATMAN_ADV_DAT 765 &batadv_attr_distributed_arp_table, 766#endif 767#ifdef CONFIG_BATMAN_ADV_MCAST 768 &batadv_attr_multicast_mode, 769#endif 770 &batadv_attr_fragmentation, 771 &batadv_attr_routing_algo, 772 &batadv_attr_gw_mode, 773 &batadv_attr_orig_interval, 774 &batadv_attr_hop_penalty, 775 &batadv_attr_gw_sel_class, 776 &batadv_attr_gw_bandwidth, 777#ifdef CONFIG_BATMAN_ADV_DEBUG 778 &batadv_attr_log_level, 779#endif 780#ifdef CONFIG_BATMAN_ADV_NC 781 &batadv_attr_network_coding, 782#endif 783 &batadv_attr_isolation_mark, 784 NULL, 785}; 786 787BATADV_ATTR_VLAN_BOOL(ap_isolation, 0644, NULL); 788 789/* array of vlan specific sysfs attributes */ 790static struct batadv_attribute *batadv_vlan_attrs[] = { 791 &batadv_attr_vlan_ap_isolation, 792 NULL, 793}; 794 795/** 796 * batadv_sysfs_add_meshif() - Add soft interface specific sysfs entries 797 * @dev: netdev struct of the soft interface 798 * 799 * Return: 0 on success or negative error number in case of failure 800 */ 801int batadv_sysfs_add_meshif(struct net_device *dev) 802{ 803 struct kobject *batif_kobject = &dev->dev.kobj; 804 struct batadv_priv *bat_priv = netdev_priv(dev); 805 struct batadv_attribute **bat_attr; 806 int err; 807 808 bat_priv->mesh_obj = kobject_create_and_add(BATADV_SYSFS_IF_MESH_SUBDIR, 809 batif_kobject); 810 if (!bat_priv->mesh_obj) { 811 batadv_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, 812 BATADV_SYSFS_IF_MESH_SUBDIR); 813 goto out; 814 } 815 816 for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr) { 817 err = sysfs_create_file(bat_priv->mesh_obj, 818 &((*bat_attr)->attr)); 819 if (err) { 820 batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n", 821 dev->name, BATADV_SYSFS_IF_MESH_SUBDIR, 822 ((*bat_attr)->attr).name); 823 goto rem_attr; 824 } 825 } 826 827 return 0; 828 829rem_attr: 830 for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr) 831 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); 832 833 kobject_uevent(bat_priv->mesh_obj, KOBJ_REMOVE); 834 kobject_del(bat_priv->mesh_obj); 835 kobject_put(bat_priv->mesh_obj); 836 bat_priv->mesh_obj = NULL; 837out: 838 return -ENOMEM; 839} 840 841/** 842 * batadv_sysfs_del_meshif() - Remove soft interface specific sysfs entries 843 * @dev: netdev struct of the soft interface 844 */ 845void batadv_sysfs_del_meshif(struct net_device *dev) 846{ 847 struct batadv_priv *bat_priv = netdev_priv(dev); 848 struct batadv_attribute **bat_attr; 849 850 for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr) 851 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); 852 853 kobject_uevent(bat_priv->mesh_obj, KOBJ_REMOVE); 854 kobject_del(bat_priv->mesh_obj); 855 kobject_put(bat_priv->mesh_obj); 856 bat_priv->mesh_obj = NULL; 857} 858 859/** 860 * batadv_sysfs_add_vlan() - add all the needed sysfs objects for the new vlan 861 * @dev: netdev of the mesh interface 862 * @vlan: private data of the newly added VLAN interface 863 * 864 * Return: 0 on success and -ENOMEM if any of the structure allocations fails. 865 */ 866int batadv_sysfs_add_vlan(struct net_device *dev, 867 struct batadv_softif_vlan *vlan) 868{ 869 char vlan_subdir[sizeof(BATADV_SYSFS_VLAN_SUBDIR_PREFIX) + 5]; 870 struct batadv_priv *bat_priv = netdev_priv(dev); 871 struct batadv_attribute **bat_attr; 872 int err; 873 874 if (vlan->vid & BATADV_VLAN_HAS_TAG) { 875 sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%hu", 876 vlan->vid & VLAN_VID_MASK); 877 878 vlan->kobj = kobject_create_and_add(vlan_subdir, 879 bat_priv->mesh_obj); 880 if (!vlan->kobj) { 881 batadv_err(dev, "Can't add sysfs directory: %s/%s\n", 882 dev->name, vlan_subdir); 883 goto out; 884 } 885 } else { 886 /* the untagged LAN uses the root folder to store its "VLAN 887 * specific attributes" 888 */ 889 vlan->kobj = bat_priv->mesh_obj; 890 kobject_get(bat_priv->mesh_obj); 891 } 892 893 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) { 894 err = sysfs_create_file(vlan->kobj, 895 &((*bat_attr)->attr)); 896 if (err) { 897 batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n", 898 dev->name, vlan_subdir, 899 ((*bat_attr)->attr).name); 900 goto rem_attr; 901 } 902 } 903 904 return 0; 905 906rem_attr: 907 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) 908 sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr)); 909 910 if (vlan->kobj != bat_priv->mesh_obj) { 911 kobject_uevent(vlan->kobj, KOBJ_REMOVE); 912 kobject_del(vlan->kobj); 913 } 914 kobject_put(vlan->kobj); 915 vlan->kobj = NULL; 916out: 917 return -ENOMEM; 918} 919 920/** 921 * batadv_sysfs_del_vlan() - remove all the sysfs objects for a given VLAN 922 * @bat_priv: the bat priv with all the soft interface information 923 * @vlan: the private data of the VLAN to destroy 924 */ 925void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv, 926 struct batadv_softif_vlan *vlan) 927{ 928 struct batadv_attribute **bat_attr; 929 930 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) 931 sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr)); 932 933 if (vlan->kobj != bat_priv->mesh_obj) { 934 kobject_uevent(vlan->kobj, KOBJ_REMOVE); 935 kobject_del(vlan->kobj); 936 } 937 kobject_put(vlan->kobj); 938 vlan->kobj = NULL; 939} 940 941static ssize_t batadv_show_mesh_iface(struct kobject *kobj, 942 struct attribute *attr, char *buff) 943{ 944 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); 945 struct batadv_hard_iface *hard_iface; 946 ssize_t length; 947 const char *ifname; 948 949 batadv_sysfs_deprecated(attr); 950 951 hard_iface = batadv_hardif_get_by_netdev(net_dev); 952 if (!hard_iface) 953 return 0; 954 955 if (hard_iface->if_status == BATADV_IF_NOT_IN_USE) 956 ifname = "none"; 957 else 958 ifname = hard_iface->soft_iface->name; 959 960 length = sprintf(buff, "%s\n", ifname); 961 962 batadv_hardif_put(hard_iface); 963 964 return length; 965} 966 967/** 968 * batadv_store_mesh_iface_finish() - store new hardif mesh_iface state 969 * @net_dev: netdevice to add/remove to/from batman-adv soft-interface 970 * @ifname: name of soft-interface to modify 971 * 972 * Changes the parts of the hard+soft interface which can not be modified under 973 * sysfs lock (to prevent deadlock situations). 974 * 975 * Return: 0 on success, 0 < on failure 976 */ 977static int batadv_store_mesh_iface_finish(struct net_device *net_dev, 978 char ifname[IFNAMSIZ]) 979{ 980 struct net *net = dev_net(net_dev); 981 struct batadv_hard_iface *hard_iface; 982 int status_tmp; 983 int ret = 0; 984 985 ASSERT_RTNL(); 986 987 hard_iface = batadv_hardif_get_by_netdev(net_dev); 988 if (!hard_iface) 989 return 0; 990 991 if (strncmp(ifname, "none", 4) == 0) 992 status_tmp = BATADV_IF_NOT_IN_USE; 993 else 994 status_tmp = BATADV_IF_I_WANT_YOU; 995 996 if (hard_iface->if_status == status_tmp) 997 goto out; 998 999 if (hard_iface->soft_iface && 1000 strncmp(hard_iface->soft_iface->name, ifname, IFNAMSIZ) == 0) 1001 goto out; 1002 1003 if (status_tmp == BATADV_IF_NOT_IN_USE) { 1004 batadv_hardif_disable_interface(hard_iface, 1005 BATADV_IF_CLEANUP_AUTO); 1006 goto out; 1007 } 1008 1009 /* if the interface already is in use */ 1010 if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) 1011 batadv_hardif_disable_interface(hard_iface, 1012 BATADV_IF_CLEANUP_AUTO); 1013 1014 ret = batadv_hardif_enable_interface(hard_iface, net, ifname); 1015out: 1016 batadv_hardif_put(hard_iface); 1017 return ret; 1018} 1019 1020/** 1021 * batadv_store_mesh_iface_work() - store new hardif mesh_iface state 1022 * @work: work queue item 1023 * 1024 * Changes the parts of the hard+soft interface which can not be modified under 1025 * sysfs lock (to prevent deadlock situations). 1026 */ 1027static void batadv_store_mesh_iface_work(struct work_struct *work) 1028{ 1029 struct batadv_store_mesh_work *store_work; 1030 int ret; 1031 1032 store_work = container_of(work, struct batadv_store_mesh_work, work); 1033 1034 rtnl_lock(); 1035 ret = batadv_store_mesh_iface_finish(store_work->net_dev, 1036 store_work->soft_iface_name); 1037 rtnl_unlock(); 1038 1039 if (ret < 0) 1040 pr_err("Failed to store new mesh_iface state %s for %s: %d\n", 1041 store_work->soft_iface_name, store_work->net_dev->name, 1042 ret); 1043 1044 dev_put(store_work->net_dev); 1045 kfree(store_work); 1046} 1047 1048static ssize_t batadv_store_mesh_iface(struct kobject *kobj, 1049 struct attribute *attr, char *buff, 1050 size_t count) 1051{ 1052 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); 1053 struct batadv_store_mesh_work *store_work; 1054 1055 batadv_sysfs_deprecated(attr); 1056 1057 if (buff[count - 1] == '\n') 1058 buff[count - 1] = '\0'; 1059 1060 if (strlen(buff) >= IFNAMSIZ) { 1061 pr_err("Invalid parameter for 'mesh_iface' setting received: interface name too long '%s'\n", 1062 buff); 1063 return -EINVAL; 1064 } 1065 1066 store_work = kmalloc(sizeof(*store_work), GFP_KERNEL); 1067 if (!store_work) 1068 return -ENOMEM; 1069 1070 dev_hold(net_dev); 1071 INIT_WORK(&store_work->work, batadv_store_mesh_iface_work); 1072 store_work->net_dev = net_dev; 1073 strscpy(store_work->soft_iface_name, buff, 1074 sizeof(store_work->soft_iface_name)); 1075 1076 queue_work(batadv_event_workqueue, &store_work->work); 1077 1078 return count; 1079} 1080 1081static ssize_t batadv_show_iface_status(struct kobject *kobj, 1082 struct attribute *attr, char *buff) 1083{ 1084 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); 1085 struct batadv_hard_iface *hard_iface; 1086 ssize_t length; 1087 1088 batadv_sysfs_deprecated(attr); 1089 1090 hard_iface = batadv_hardif_get_by_netdev(net_dev); 1091 if (!hard_iface) 1092 return 0; 1093 1094 switch (hard_iface->if_status) { 1095 case BATADV_IF_TO_BE_REMOVED: 1096 length = sprintf(buff, "disabling\n"); 1097 break; 1098 case BATADV_IF_INACTIVE: 1099 length = sprintf(buff, "inactive\n"); 1100 break; 1101 case BATADV_IF_ACTIVE: 1102 length = sprintf(buff, "active\n"); 1103 break; 1104 case BATADV_IF_TO_BE_ACTIVATED: 1105 length = sprintf(buff, "enabling\n"); 1106 break; 1107 case BATADV_IF_NOT_IN_USE: 1108 default: 1109 length = sprintf(buff, "not in use\n"); 1110 break; 1111 } 1112 1113 batadv_hardif_put(hard_iface); 1114 1115 return length; 1116} 1117 1118#ifdef CONFIG_BATMAN_ADV_BATMAN_V 1119 1120/** 1121 * batadv_store_throughput_override() - parse and store throughput override 1122 * entered by the user 1123 * @kobj: kobject representing the private mesh sysfs directory 1124 * @attr: the batman-adv attribute the user is interacting with 1125 * @buff: the buffer containing the user data 1126 * @count: number of bytes in the buffer 1127 * 1128 * Return: 'count' on success or a negative error code in case of failure 1129 */ 1130static ssize_t batadv_store_throughput_override(struct kobject *kobj, 1131 struct attribute *attr, 1132 char *buff, size_t count) 1133{ 1134 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); 1135 struct batadv_hard_iface *hard_iface; 1136 struct batadv_priv *bat_priv; 1137 u32 tp_override; 1138 u32 old_tp_override; 1139 bool ret; 1140 1141 batadv_sysfs_deprecated(attr); 1142 1143 hard_iface = batadv_hardif_get_by_netdev(net_dev); 1144 if (!hard_iface) 1145 return -EINVAL; 1146 1147 if (buff[count - 1] == '\n') 1148 buff[count - 1] = '\0'; 1149 1150 ret = batadv_parse_throughput(net_dev, buff, "throughput_override", 1151 &tp_override); 1152 if (!ret) 1153 goto out; 1154 1155 old_tp_override = atomic_read(&hard_iface->bat_v.throughput_override); 1156 if (old_tp_override == tp_override) 1157 goto out; 1158 1159 batadv_info(hard_iface->soft_iface, 1160 "%s: %s: Changing from: %u.%u MBit to: %u.%u MBit\n", 1161 "throughput_override", net_dev->name, 1162 old_tp_override / 10, old_tp_override % 10, 1163 tp_override / 10, tp_override % 10); 1164 1165 atomic_set(&hard_iface->bat_v.throughput_override, tp_override); 1166 1167 if (hard_iface->soft_iface) { 1168 bat_priv = netdev_priv(hard_iface->soft_iface); 1169 batadv_netlink_notify_hardif(bat_priv, hard_iface); 1170 } 1171 1172out: 1173 batadv_hardif_put(hard_iface); 1174 return count; 1175} 1176 1177static ssize_t batadv_show_throughput_override(struct kobject *kobj, 1178 struct attribute *attr, 1179 char *buff) 1180{ 1181 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); 1182 struct batadv_hard_iface *hard_iface; 1183 u32 tp_override; 1184 1185 batadv_sysfs_deprecated(attr); 1186 1187 hard_iface = batadv_hardif_get_by_netdev(net_dev); 1188 if (!hard_iface) 1189 return -EINVAL; 1190 1191 tp_override = atomic_read(&hard_iface->bat_v.throughput_override); 1192 1193 batadv_hardif_put(hard_iface); 1194 return sprintf(buff, "%u.%u MBit\n", tp_override / 10, 1195 tp_override % 10); 1196} 1197 1198#endif 1199 1200static BATADV_ATTR(mesh_iface, 0644, batadv_show_mesh_iface, 1201 batadv_store_mesh_iface); 1202static BATADV_ATTR(iface_status, 0444, batadv_show_iface_status, NULL); 1203#ifdef CONFIG_BATMAN_ADV_BATMAN_V 1204BATADV_ATTR_HIF_UINT(elp_interval, bat_v.elp_interval, 0644, 1205 2 * BATADV_JITTER, INT_MAX, NULL); 1206static BATADV_ATTR(throughput_override, 0644, batadv_show_throughput_override, 1207 batadv_store_throughput_override); 1208#endif 1209 1210static struct batadv_attribute *batadv_batman_attrs[] = { 1211 &batadv_attr_mesh_iface, 1212 &batadv_attr_iface_status, 1213#ifdef CONFIG_BATMAN_ADV_BATMAN_V 1214 &batadv_attr_elp_interval, 1215 &batadv_attr_throughput_override, 1216#endif 1217 NULL, 1218}; 1219 1220/** 1221 * batadv_sysfs_add_hardif() - Add hard interface specific sysfs entries 1222 * @hardif_obj: address where to store the pointer to new sysfs folder 1223 * @dev: netdev struct of the hard interface 1224 * 1225 * Return: 0 on success or negative error number in case of failure 1226 */ 1227int batadv_sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev) 1228{ 1229 struct kobject *hardif_kobject = &dev->dev.kobj; 1230 struct batadv_attribute **bat_attr; 1231 int err; 1232 1233 *hardif_obj = kobject_create_and_add(BATADV_SYSFS_IF_BAT_SUBDIR, 1234 hardif_kobject); 1235 1236 if (!*hardif_obj) { 1237 batadv_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, 1238 BATADV_SYSFS_IF_BAT_SUBDIR); 1239 goto out; 1240 } 1241 1242 for (bat_attr = batadv_batman_attrs; *bat_attr; ++bat_attr) { 1243 err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr)); 1244 if (err) { 1245 batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n", 1246 dev->name, BATADV_SYSFS_IF_BAT_SUBDIR, 1247 ((*bat_attr)->attr).name); 1248 goto rem_attr; 1249 } 1250 } 1251 1252 return 0; 1253 1254rem_attr: 1255 for (bat_attr = batadv_batman_attrs; *bat_attr; ++bat_attr) 1256 sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr)); 1257out: 1258 return -ENOMEM; 1259} 1260 1261/** 1262 * batadv_sysfs_del_hardif() - Remove hard interface specific sysfs entries 1263 * @hardif_obj: address to the pointer to which stores batman-adv sysfs folder 1264 * of the hard interface 1265 */ 1266void batadv_sysfs_del_hardif(struct kobject **hardif_obj) 1267{ 1268 kobject_uevent(*hardif_obj, KOBJ_REMOVE); 1269 kobject_del(*hardif_obj); 1270 kobject_put(*hardif_obj); 1271 *hardif_obj = NULL; 1272} 1273