garp.c (18245B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * IEEE 802.1D Generic Attribute Registration Protocol (GARP) 4 * 5 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> 6 */ 7#include <linux/kernel.h> 8#include <linux/timer.h> 9#include <linux/skbuff.h> 10#include <linux/netdevice.h> 11#include <linux/etherdevice.h> 12#include <linux/rtnetlink.h> 13#include <linux/llc.h> 14#include <linux/slab.h> 15#include <linux/module.h> 16#include <net/llc.h> 17#include <net/llc_pdu.h> 18#include <net/garp.h> 19#include <asm/unaligned.h> 20 21static unsigned int garp_join_time __read_mostly = 200; 22module_param(garp_join_time, uint, 0644); 23MODULE_PARM_DESC(garp_join_time, "Join time in ms (default 200ms)"); 24MODULE_LICENSE("GPL"); 25 26static const struct garp_state_trans { 27 u8 state; 28 u8 action; 29} garp_applicant_state_table[GARP_APPLICANT_MAX + 1][GARP_EVENT_MAX + 1] = { 30 [GARP_APPLICANT_VA] = { 31 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_AA, 32 .action = GARP_ACTION_S_JOIN_IN }, 33 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_AA }, 34 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VA }, 35 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VA }, 36 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VA }, 37 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, 38 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, 39 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_LA }, 40 }, 41 [GARP_APPLICANT_AA] = { 42 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_QA, 43 .action = GARP_ACTION_S_JOIN_IN }, 44 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QA }, 45 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VA }, 46 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VA }, 47 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VA }, 48 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, 49 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, 50 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_LA }, 51 }, 52 [GARP_APPLICANT_QA] = { 53 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, 54 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QA }, 55 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VA }, 56 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VA }, 57 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VP }, 58 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, 59 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, 60 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_LA }, 61 }, 62 [GARP_APPLICANT_LA] = { 63 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_VO, 64 .action = GARP_ACTION_S_LEAVE_EMPTY }, 65 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_LA }, 66 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VO }, 67 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_LA }, 68 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_LA }, 69 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VO }, 70 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_VA }, 71 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_INVALID }, 72 }, 73 [GARP_APPLICANT_VP] = { 74 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_AA, 75 .action = GARP_ACTION_S_JOIN_IN }, 76 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_AP }, 77 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VP }, 78 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VP }, 79 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VP }, 80 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, 81 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, 82 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_VO }, 83 }, 84 [GARP_APPLICANT_AP] = { 85 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_QA, 86 .action = GARP_ACTION_S_JOIN_IN }, 87 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QP }, 88 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VP }, 89 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VP }, 90 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VP }, 91 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, 92 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, 93 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_AO }, 94 }, 95 [GARP_APPLICANT_QP] = { 96 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, 97 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QP }, 98 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VP }, 99 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VP }, 100 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VP }, 101 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VP }, 102 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_INVALID }, 103 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_QO }, 104 }, 105 [GARP_APPLICANT_VO] = { 106 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, 107 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_AO }, 108 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VO }, 109 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VO }, 110 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VO }, 111 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VO }, 112 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_VP }, 113 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_INVALID }, 114 }, 115 [GARP_APPLICANT_AO] = { 116 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, 117 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QO }, 118 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VO }, 119 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VO }, 120 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VO }, 121 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VO }, 122 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_AP }, 123 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_INVALID }, 124 }, 125 [GARP_APPLICANT_QO] = { 126 [GARP_EVENT_TRANSMIT_PDU] = { .state = GARP_APPLICANT_INVALID }, 127 [GARP_EVENT_R_JOIN_IN] = { .state = GARP_APPLICANT_QO }, 128 [GARP_EVENT_R_JOIN_EMPTY] = { .state = GARP_APPLICANT_VO }, 129 [GARP_EVENT_R_EMPTY] = { .state = GARP_APPLICANT_VO }, 130 [GARP_EVENT_R_LEAVE_IN] = { .state = GARP_APPLICANT_VO }, 131 [GARP_EVENT_R_LEAVE_EMPTY] = { .state = GARP_APPLICANT_VO }, 132 [GARP_EVENT_REQ_JOIN] = { .state = GARP_APPLICANT_QP }, 133 [GARP_EVENT_REQ_LEAVE] = { .state = GARP_APPLICANT_INVALID }, 134 }, 135}; 136 137static int garp_attr_cmp(const struct garp_attr *attr, 138 const void *data, u8 len, u8 type) 139{ 140 if (attr->type != type) 141 return attr->type - type; 142 if (attr->dlen != len) 143 return attr->dlen - len; 144 return memcmp(attr->data, data, len); 145} 146 147static struct garp_attr *garp_attr_lookup(const struct garp_applicant *app, 148 const void *data, u8 len, u8 type) 149{ 150 struct rb_node *parent = app->gid.rb_node; 151 struct garp_attr *attr; 152 int d; 153 154 while (parent) { 155 attr = rb_entry(parent, struct garp_attr, node); 156 d = garp_attr_cmp(attr, data, len, type); 157 if (d > 0) 158 parent = parent->rb_left; 159 else if (d < 0) 160 parent = parent->rb_right; 161 else 162 return attr; 163 } 164 return NULL; 165} 166 167static struct garp_attr *garp_attr_create(struct garp_applicant *app, 168 const void *data, u8 len, u8 type) 169{ 170 struct rb_node *parent = NULL, **p = &app->gid.rb_node; 171 struct garp_attr *attr; 172 int d; 173 174 while (*p) { 175 parent = *p; 176 attr = rb_entry(parent, struct garp_attr, node); 177 d = garp_attr_cmp(attr, data, len, type); 178 if (d > 0) 179 p = &parent->rb_left; 180 else if (d < 0) 181 p = &parent->rb_right; 182 else { 183 /* The attribute already exists; re-use it. */ 184 return attr; 185 } 186 } 187 attr = kmalloc(sizeof(*attr) + len, GFP_ATOMIC); 188 if (!attr) 189 return attr; 190 attr->state = GARP_APPLICANT_VO; 191 attr->type = type; 192 attr->dlen = len; 193 memcpy(attr->data, data, len); 194 195 rb_link_node(&attr->node, parent, p); 196 rb_insert_color(&attr->node, &app->gid); 197 return attr; 198} 199 200static void garp_attr_destroy(struct garp_applicant *app, struct garp_attr *attr) 201{ 202 rb_erase(&attr->node, &app->gid); 203 kfree(attr); 204} 205 206static void garp_attr_destroy_all(struct garp_applicant *app) 207{ 208 struct rb_node *node, *next; 209 struct garp_attr *attr; 210 211 for (node = rb_first(&app->gid); 212 next = node ? rb_next(node) : NULL, node != NULL; 213 node = next) { 214 attr = rb_entry(node, struct garp_attr, node); 215 garp_attr_destroy(app, attr); 216 } 217} 218 219static int garp_pdu_init(struct garp_applicant *app) 220{ 221 struct sk_buff *skb; 222 struct garp_pdu_hdr *gp; 223 224#define LLC_RESERVE sizeof(struct llc_pdu_un) 225 skb = alloc_skb(app->dev->mtu + LL_RESERVED_SPACE(app->dev), 226 GFP_ATOMIC); 227 if (!skb) 228 return -ENOMEM; 229 230 skb->dev = app->dev; 231 skb->protocol = htons(ETH_P_802_2); 232 skb_reserve(skb, LL_RESERVED_SPACE(app->dev) + LLC_RESERVE); 233 234 gp = __skb_put(skb, sizeof(*gp)); 235 put_unaligned(htons(GARP_PROTOCOL_ID), &gp->protocol); 236 237 app->pdu = skb; 238 return 0; 239} 240 241static int garp_pdu_append_end_mark(struct garp_applicant *app) 242{ 243 if (skb_tailroom(app->pdu) < sizeof(u8)) 244 return -1; 245 __skb_put_u8(app->pdu, GARP_END_MARK); 246 return 0; 247} 248 249static void garp_pdu_queue(struct garp_applicant *app) 250{ 251 if (!app->pdu) 252 return; 253 254 garp_pdu_append_end_mark(app); 255 garp_pdu_append_end_mark(app); 256 257 llc_pdu_header_init(app->pdu, LLC_PDU_TYPE_U, LLC_SAP_BSPAN, 258 LLC_SAP_BSPAN, LLC_PDU_CMD); 259 llc_pdu_init_as_ui_cmd(app->pdu); 260 llc_mac_hdr_init(app->pdu, app->dev->dev_addr, 261 app->app->proto.group_address); 262 263 skb_queue_tail(&app->queue, app->pdu); 264 app->pdu = NULL; 265} 266 267static void garp_queue_xmit(struct garp_applicant *app) 268{ 269 struct sk_buff *skb; 270 271 while ((skb = skb_dequeue(&app->queue))) 272 dev_queue_xmit(skb); 273} 274 275static int garp_pdu_append_msg(struct garp_applicant *app, u8 attrtype) 276{ 277 struct garp_msg_hdr *gm; 278 279 if (skb_tailroom(app->pdu) < sizeof(*gm)) 280 return -1; 281 gm = __skb_put(app->pdu, sizeof(*gm)); 282 gm->attrtype = attrtype; 283 garp_cb(app->pdu)->cur_type = attrtype; 284 return 0; 285} 286 287static int garp_pdu_append_attr(struct garp_applicant *app, 288 const struct garp_attr *attr, 289 enum garp_attr_event event) 290{ 291 struct garp_attr_hdr *ga; 292 unsigned int len; 293 int err; 294again: 295 if (!app->pdu) { 296 err = garp_pdu_init(app); 297 if (err < 0) 298 return err; 299 } 300 301 if (garp_cb(app->pdu)->cur_type != attr->type) { 302 if (garp_cb(app->pdu)->cur_type && 303 garp_pdu_append_end_mark(app) < 0) 304 goto queue; 305 if (garp_pdu_append_msg(app, attr->type) < 0) 306 goto queue; 307 } 308 309 len = sizeof(*ga) + attr->dlen; 310 if (skb_tailroom(app->pdu) < len) 311 goto queue; 312 ga = __skb_put(app->pdu, len); 313 ga->len = len; 314 ga->event = event; 315 memcpy(ga->data, attr->data, attr->dlen); 316 return 0; 317 318queue: 319 garp_pdu_queue(app); 320 goto again; 321} 322 323static void garp_attr_event(struct garp_applicant *app, 324 struct garp_attr *attr, enum garp_event event) 325{ 326 enum garp_applicant_state state; 327 328 state = garp_applicant_state_table[attr->state][event].state; 329 if (state == GARP_APPLICANT_INVALID) 330 return; 331 332 switch (garp_applicant_state_table[attr->state][event].action) { 333 case GARP_ACTION_NONE: 334 break; 335 case GARP_ACTION_S_JOIN_IN: 336 /* When appending the attribute fails, don't update state in 337 * order to retry on next TRANSMIT_PDU event. */ 338 if (garp_pdu_append_attr(app, attr, GARP_JOIN_IN) < 0) 339 return; 340 break; 341 case GARP_ACTION_S_LEAVE_EMPTY: 342 garp_pdu_append_attr(app, attr, GARP_LEAVE_EMPTY); 343 /* As a pure applicant, sending a leave message implies that 344 * the attribute was unregistered and can be destroyed. */ 345 garp_attr_destroy(app, attr); 346 return; 347 default: 348 WARN_ON(1); 349 } 350 351 attr->state = state; 352} 353 354int garp_request_join(const struct net_device *dev, 355 const struct garp_application *appl, 356 const void *data, u8 len, u8 type) 357{ 358 struct garp_port *port = rtnl_dereference(dev->garp_port); 359 struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]); 360 struct garp_attr *attr; 361 362 spin_lock_bh(&app->lock); 363 attr = garp_attr_create(app, data, len, type); 364 if (!attr) { 365 spin_unlock_bh(&app->lock); 366 return -ENOMEM; 367 } 368 garp_attr_event(app, attr, GARP_EVENT_REQ_JOIN); 369 spin_unlock_bh(&app->lock); 370 return 0; 371} 372EXPORT_SYMBOL_GPL(garp_request_join); 373 374void garp_request_leave(const struct net_device *dev, 375 const struct garp_application *appl, 376 const void *data, u8 len, u8 type) 377{ 378 struct garp_port *port = rtnl_dereference(dev->garp_port); 379 struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]); 380 struct garp_attr *attr; 381 382 spin_lock_bh(&app->lock); 383 attr = garp_attr_lookup(app, data, len, type); 384 if (!attr) { 385 spin_unlock_bh(&app->lock); 386 return; 387 } 388 garp_attr_event(app, attr, GARP_EVENT_REQ_LEAVE); 389 spin_unlock_bh(&app->lock); 390} 391EXPORT_SYMBOL_GPL(garp_request_leave); 392 393static void garp_gid_event(struct garp_applicant *app, enum garp_event event) 394{ 395 struct rb_node *node, *next; 396 struct garp_attr *attr; 397 398 for (node = rb_first(&app->gid); 399 next = node ? rb_next(node) : NULL, node != NULL; 400 node = next) { 401 attr = rb_entry(node, struct garp_attr, node); 402 garp_attr_event(app, attr, event); 403 } 404} 405 406static void garp_join_timer_arm(struct garp_applicant *app) 407{ 408 unsigned long delay; 409 410 delay = (u64)msecs_to_jiffies(garp_join_time) * prandom_u32() >> 32; 411 mod_timer(&app->join_timer, jiffies + delay); 412} 413 414static void garp_join_timer(struct timer_list *t) 415{ 416 struct garp_applicant *app = from_timer(app, t, join_timer); 417 418 spin_lock(&app->lock); 419 garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU); 420 garp_pdu_queue(app); 421 spin_unlock(&app->lock); 422 423 garp_queue_xmit(app); 424 garp_join_timer_arm(app); 425} 426 427static int garp_pdu_parse_end_mark(struct sk_buff *skb) 428{ 429 if (!pskb_may_pull(skb, sizeof(u8))) 430 return -1; 431 if (*skb->data == GARP_END_MARK) { 432 skb_pull(skb, sizeof(u8)); 433 return -1; 434 } 435 return 0; 436} 437 438static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb, 439 u8 attrtype) 440{ 441 const struct garp_attr_hdr *ga; 442 struct garp_attr *attr; 443 enum garp_event event; 444 unsigned int dlen; 445 446 if (!pskb_may_pull(skb, sizeof(*ga))) 447 return -1; 448 ga = (struct garp_attr_hdr *)skb->data; 449 if (ga->len < sizeof(*ga)) 450 return -1; 451 452 if (!pskb_may_pull(skb, ga->len)) 453 return -1; 454 skb_pull(skb, ga->len); 455 dlen = sizeof(*ga) - ga->len; 456 457 if (attrtype > app->app->maxattr) 458 return 0; 459 460 switch (ga->event) { 461 case GARP_LEAVE_ALL: 462 if (dlen != 0) 463 return -1; 464 garp_gid_event(app, GARP_EVENT_R_LEAVE_EMPTY); 465 return 0; 466 case GARP_JOIN_EMPTY: 467 event = GARP_EVENT_R_JOIN_EMPTY; 468 break; 469 case GARP_JOIN_IN: 470 event = GARP_EVENT_R_JOIN_IN; 471 break; 472 case GARP_LEAVE_EMPTY: 473 event = GARP_EVENT_R_LEAVE_EMPTY; 474 break; 475 case GARP_EMPTY: 476 event = GARP_EVENT_R_EMPTY; 477 break; 478 default: 479 return 0; 480 } 481 482 if (dlen == 0) 483 return -1; 484 attr = garp_attr_lookup(app, ga->data, dlen, attrtype); 485 if (attr == NULL) 486 return 0; 487 garp_attr_event(app, attr, event); 488 return 0; 489} 490 491static int garp_pdu_parse_msg(struct garp_applicant *app, struct sk_buff *skb) 492{ 493 const struct garp_msg_hdr *gm; 494 495 if (!pskb_may_pull(skb, sizeof(*gm))) 496 return -1; 497 gm = (struct garp_msg_hdr *)skb->data; 498 if (gm->attrtype == 0) 499 return -1; 500 skb_pull(skb, sizeof(*gm)); 501 502 while (skb->len > 0) { 503 if (garp_pdu_parse_attr(app, skb, gm->attrtype) < 0) 504 return -1; 505 if (garp_pdu_parse_end_mark(skb) < 0) 506 break; 507 } 508 return 0; 509} 510 511static void garp_pdu_rcv(const struct stp_proto *proto, struct sk_buff *skb, 512 struct net_device *dev) 513{ 514 struct garp_application *appl = proto->data; 515 struct garp_port *port; 516 struct garp_applicant *app; 517 const struct garp_pdu_hdr *gp; 518 519 port = rcu_dereference(dev->garp_port); 520 if (!port) 521 goto err; 522 app = rcu_dereference(port->applicants[appl->type]); 523 if (!app) 524 goto err; 525 526 if (!pskb_may_pull(skb, sizeof(*gp))) 527 goto err; 528 gp = (struct garp_pdu_hdr *)skb->data; 529 if (get_unaligned(&gp->protocol) != htons(GARP_PROTOCOL_ID)) 530 goto err; 531 skb_pull(skb, sizeof(*gp)); 532 533 spin_lock(&app->lock); 534 while (skb->len > 0) { 535 if (garp_pdu_parse_msg(app, skb) < 0) 536 break; 537 if (garp_pdu_parse_end_mark(skb) < 0) 538 break; 539 } 540 spin_unlock(&app->lock); 541err: 542 kfree_skb(skb); 543} 544 545static int garp_init_port(struct net_device *dev) 546{ 547 struct garp_port *port; 548 549 port = kzalloc(sizeof(*port), GFP_KERNEL); 550 if (!port) 551 return -ENOMEM; 552 rcu_assign_pointer(dev->garp_port, port); 553 return 0; 554} 555 556static void garp_release_port(struct net_device *dev) 557{ 558 struct garp_port *port = rtnl_dereference(dev->garp_port); 559 unsigned int i; 560 561 for (i = 0; i <= GARP_APPLICATION_MAX; i++) { 562 if (rtnl_dereference(port->applicants[i])) 563 return; 564 } 565 RCU_INIT_POINTER(dev->garp_port, NULL); 566 kfree_rcu(port, rcu); 567} 568 569int garp_init_applicant(struct net_device *dev, struct garp_application *appl) 570{ 571 struct garp_applicant *app; 572 int err; 573 574 ASSERT_RTNL(); 575 576 if (!rtnl_dereference(dev->garp_port)) { 577 err = garp_init_port(dev); 578 if (err < 0) 579 goto err1; 580 } 581 582 err = -ENOMEM; 583 app = kzalloc(sizeof(*app), GFP_KERNEL); 584 if (!app) 585 goto err2; 586 587 err = dev_mc_add(dev, appl->proto.group_address); 588 if (err < 0) 589 goto err3; 590 591 app->dev = dev; 592 app->app = appl; 593 app->gid = RB_ROOT; 594 spin_lock_init(&app->lock); 595 skb_queue_head_init(&app->queue); 596 rcu_assign_pointer(dev->garp_port->applicants[appl->type], app); 597 timer_setup(&app->join_timer, garp_join_timer, 0); 598 garp_join_timer_arm(app); 599 return 0; 600 601err3: 602 kfree(app); 603err2: 604 garp_release_port(dev); 605err1: 606 return err; 607} 608EXPORT_SYMBOL_GPL(garp_init_applicant); 609 610void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl) 611{ 612 struct garp_port *port = rtnl_dereference(dev->garp_port); 613 struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]); 614 615 ASSERT_RTNL(); 616 617 RCU_INIT_POINTER(port->applicants[appl->type], NULL); 618 619 /* Delete timer and generate a final TRANSMIT_PDU event to flush out 620 * all pending messages before the applicant is gone. */ 621 del_timer_sync(&app->join_timer); 622 623 spin_lock_bh(&app->lock); 624 garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU); 625 garp_attr_destroy_all(app); 626 garp_pdu_queue(app); 627 spin_unlock_bh(&app->lock); 628 629 garp_queue_xmit(app); 630 631 dev_mc_del(dev, appl->proto.group_address); 632 kfree_rcu(app, rcu); 633 garp_release_port(dev); 634} 635EXPORT_SYMBOL_GPL(garp_uninit_applicant); 636 637int garp_register_application(struct garp_application *appl) 638{ 639 appl->proto.rcv = garp_pdu_rcv; 640 appl->proto.data = appl; 641 return stp_proto_register(&appl->proto); 642} 643EXPORT_SYMBOL_GPL(garp_register_application); 644 645void garp_unregister_application(struct garp_application *appl) 646{ 647 stp_proto_unregister(&appl->proto); 648} 649EXPORT_SYMBOL_GPL(garp_unregister_application);