root/net/802/garp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. garp_attr_cmp
  2. garp_attr_lookup
  3. garp_attr_create
  4. garp_attr_destroy
  5. garp_pdu_init
  6. garp_pdu_append_end_mark
  7. garp_pdu_queue
  8. garp_queue_xmit
  9. garp_pdu_append_msg
  10. garp_pdu_append_attr
  11. garp_attr_event
  12. garp_request_join
  13. garp_request_leave
  14. garp_gid_event
  15. garp_join_timer_arm
  16. garp_join_timer
  17. garp_pdu_parse_end_mark
  18. garp_pdu_parse_attr
  19. garp_pdu_parse_msg
  20. garp_pdu_rcv
  21. garp_init_port
  22. garp_release_port
  23. garp_init_applicant
  24. garp_uninit_applicant
  25. garp_register_application
  26. garp_unregister_application

   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 
  21 static unsigned int garp_join_time __read_mostly = 200;
  22 module_param(garp_join_time, uint, 0644);
  23 MODULE_PARM_DESC(garp_join_time, "Join time in ms (default 200ms)");
  24 MODULE_LICENSE("GPL");
  25 
  26 static 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 
 137 static 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 
 147 static 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 
 167 static 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 
 200 static 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 
 206 static int garp_pdu_init(struct garp_applicant *app)
 207 {
 208         struct sk_buff *skb;
 209         struct garp_pdu_hdr *gp;
 210 
 211 #define LLC_RESERVE     sizeof(struct llc_pdu_un)
 212         skb = alloc_skb(app->dev->mtu + LL_RESERVED_SPACE(app->dev),
 213                         GFP_ATOMIC);
 214         if (!skb)
 215                 return -ENOMEM;
 216 
 217         skb->dev = app->dev;
 218         skb->protocol = htons(ETH_P_802_2);
 219         skb_reserve(skb, LL_RESERVED_SPACE(app->dev) + LLC_RESERVE);
 220 
 221         gp = __skb_put(skb, sizeof(*gp));
 222         put_unaligned(htons(GARP_PROTOCOL_ID), &gp->protocol);
 223 
 224         app->pdu = skb;
 225         return 0;
 226 }
 227 
 228 static int garp_pdu_append_end_mark(struct garp_applicant *app)
 229 {
 230         if (skb_tailroom(app->pdu) < sizeof(u8))
 231                 return -1;
 232         __skb_put_u8(app->pdu, GARP_END_MARK);
 233         return 0;
 234 }
 235 
 236 static void garp_pdu_queue(struct garp_applicant *app)
 237 {
 238         if (!app->pdu)
 239                 return;
 240 
 241         garp_pdu_append_end_mark(app);
 242         garp_pdu_append_end_mark(app);
 243 
 244         llc_pdu_header_init(app->pdu, LLC_PDU_TYPE_U, LLC_SAP_BSPAN,
 245                             LLC_SAP_BSPAN, LLC_PDU_CMD);
 246         llc_pdu_init_as_ui_cmd(app->pdu);
 247         llc_mac_hdr_init(app->pdu, app->dev->dev_addr,
 248                          app->app->proto.group_address);
 249 
 250         skb_queue_tail(&app->queue, app->pdu);
 251         app->pdu = NULL;
 252 }
 253 
 254 static void garp_queue_xmit(struct garp_applicant *app)
 255 {
 256         struct sk_buff *skb;
 257 
 258         while ((skb = skb_dequeue(&app->queue)))
 259                 dev_queue_xmit(skb);
 260 }
 261 
 262 static int garp_pdu_append_msg(struct garp_applicant *app, u8 attrtype)
 263 {
 264         struct garp_msg_hdr *gm;
 265 
 266         if (skb_tailroom(app->pdu) < sizeof(*gm))
 267                 return -1;
 268         gm = __skb_put(app->pdu, sizeof(*gm));
 269         gm->attrtype = attrtype;
 270         garp_cb(app->pdu)->cur_type = attrtype;
 271         return 0;
 272 }
 273 
 274 static int garp_pdu_append_attr(struct garp_applicant *app,
 275                                 const struct garp_attr *attr,
 276                                 enum garp_attr_event event)
 277 {
 278         struct garp_attr_hdr *ga;
 279         unsigned int len;
 280         int err;
 281 again:
 282         if (!app->pdu) {
 283                 err = garp_pdu_init(app);
 284                 if (err < 0)
 285                         return err;
 286         }
 287 
 288         if (garp_cb(app->pdu)->cur_type != attr->type) {
 289                 if (garp_cb(app->pdu)->cur_type &&
 290                     garp_pdu_append_end_mark(app) < 0)
 291                         goto queue;
 292                 if (garp_pdu_append_msg(app, attr->type) < 0)
 293                         goto queue;
 294         }
 295 
 296         len = sizeof(*ga) + attr->dlen;
 297         if (skb_tailroom(app->pdu) < len)
 298                 goto queue;
 299         ga = __skb_put(app->pdu, len);
 300         ga->len   = len;
 301         ga->event = event;
 302         memcpy(ga->data, attr->data, attr->dlen);
 303         return 0;
 304 
 305 queue:
 306         garp_pdu_queue(app);
 307         goto again;
 308 }
 309 
 310 static void garp_attr_event(struct garp_applicant *app,
 311                             struct garp_attr *attr, enum garp_event event)
 312 {
 313         enum garp_applicant_state state;
 314 
 315         state = garp_applicant_state_table[attr->state][event].state;
 316         if (state == GARP_APPLICANT_INVALID)
 317                 return;
 318 
 319         switch (garp_applicant_state_table[attr->state][event].action) {
 320         case GARP_ACTION_NONE:
 321                 break;
 322         case GARP_ACTION_S_JOIN_IN:
 323                 /* When appending the attribute fails, don't update state in
 324                  * order to retry on next TRANSMIT_PDU event. */
 325                 if (garp_pdu_append_attr(app, attr, GARP_JOIN_IN) < 0)
 326                         return;
 327                 break;
 328         case GARP_ACTION_S_LEAVE_EMPTY:
 329                 garp_pdu_append_attr(app, attr, GARP_LEAVE_EMPTY);
 330                 /* As a pure applicant, sending a leave message implies that
 331                  * the attribute was unregistered and can be destroyed. */
 332                 garp_attr_destroy(app, attr);
 333                 return;
 334         default:
 335                 WARN_ON(1);
 336         }
 337 
 338         attr->state = state;
 339 }
 340 
 341 int garp_request_join(const struct net_device *dev,
 342                       const struct garp_application *appl,
 343                       const void *data, u8 len, u8 type)
 344 {
 345         struct garp_port *port = rtnl_dereference(dev->garp_port);
 346         struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
 347         struct garp_attr *attr;
 348 
 349         spin_lock_bh(&app->lock);
 350         attr = garp_attr_create(app, data, len, type);
 351         if (!attr) {
 352                 spin_unlock_bh(&app->lock);
 353                 return -ENOMEM;
 354         }
 355         garp_attr_event(app, attr, GARP_EVENT_REQ_JOIN);
 356         spin_unlock_bh(&app->lock);
 357         return 0;
 358 }
 359 EXPORT_SYMBOL_GPL(garp_request_join);
 360 
 361 void garp_request_leave(const struct net_device *dev,
 362                         const struct garp_application *appl,
 363                         const void *data, u8 len, u8 type)
 364 {
 365         struct garp_port *port = rtnl_dereference(dev->garp_port);
 366         struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
 367         struct garp_attr *attr;
 368 
 369         spin_lock_bh(&app->lock);
 370         attr = garp_attr_lookup(app, data, len, type);
 371         if (!attr) {
 372                 spin_unlock_bh(&app->lock);
 373                 return;
 374         }
 375         garp_attr_event(app, attr, GARP_EVENT_REQ_LEAVE);
 376         spin_unlock_bh(&app->lock);
 377 }
 378 EXPORT_SYMBOL_GPL(garp_request_leave);
 379 
 380 static void garp_gid_event(struct garp_applicant *app, enum garp_event event)
 381 {
 382         struct rb_node *node, *next;
 383         struct garp_attr *attr;
 384 
 385         for (node = rb_first(&app->gid);
 386              next = node ? rb_next(node) : NULL, node != NULL;
 387              node = next) {
 388                 attr = rb_entry(node, struct garp_attr, node);
 389                 garp_attr_event(app, attr, event);
 390         }
 391 }
 392 
 393 static void garp_join_timer_arm(struct garp_applicant *app)
 394 {
 395         unsigned long delay;
 396 
 397         delay = (u64)msecs_to_jiffies(garp_join_time) * prandom_u32() >> 32;
 398         mod_timer(&app->join_timer, jiffies + delay);
 399 }
 400 
 401 static void garp_join_timer(struct timer_list *t)
 402 {
 403         struct garp_applicant *app = from_timer(app, t, join_timer);
 404 
 405         spin_lock(&app->lock);
 406         garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU);
 407         garp_pdu_queue(app);
 408         spin_unlock(&app->lock);
 409 
 410         garp_queue_xmit(app);
 411         garp_join_timer_arm(app);
 412 }
 413 
 414 static int garp_pdu_parse_end_mark(struct sk_buff *skb)
 415 {
 416         if (!pskb_may_pull(skb, sizeof(u8)))
 417                 return -1;
 418         if (*skb->data == GARP_END_MARK) {
 419                 skb_pull(skb, sizeof(u8));
 420                 return -1;
 421         }
 422         return 0;
 423 }
 424 
 425 static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb,
 426                                u8 attrtype)
 427 {
 428         const struct garp_attr_hdr *ga;
 429         struct garp_attr *attr;
 430         enum garp_event event;
 431         unsigned int dlen;
 432 
 433         if (!pskb_may_pull(skb, sizeof(*ga)))
 434                 return -1;
 435         ga = (struct garp_attr_hdr *)skb->data;
 436         if (ga->len < sizeof(*ga))
 437                 return -1;
 438 
 439         if (!pskb_may_pull(skb, ga->len))
 440                 return -1;
 441         skb_pull(skb, ga->len);
 442         dlen = sizeof(*ga) - ga->len;
 443 
 444         if (attrtype > app->app->maxattr)
 445                 return 0;
 446 
 447         switch (ga->event) {
 448         case GARP_LEAVE_ALL:
 449                 if (dlen != 0)
 450                         return -1;
 451                 garp_gid_event(app, GARP_EVENT_R_LEAVE_EMPTY);
 452                 return 0;
 453         case GARP_JOIN_EMPTY:
 454                 event = GARP_EVENT_R_JOIN_EMPTY;
 455                 break;
 456         case GARP_JOIN_IN:
 457                 event = GARP_EVENT_R_JOIN_IN;
 458                 break;
 459         case GARP_LEAVE_EMPTY:
 460                 event = GARP_EVENT_R_LEAVE_EMPTY;
 461                 break;
 462         case GARP_EMPTY:
 463                 event = GARP_EVENT_R_EMPTY;
 464                 break;
 465         default:
 466                 return 0;
 467         }
 468 
 469         if (dlen == 0)
 470                 return -1;
 471         attr = garp_attr_lookup(app, ga->data, dlen, attrtype);
 472         if (attr == NULL)
 473                 return 0;
 474         garp_attr_event(app, attr, event);
 475         return 0;
 476 }
 477 
 478 static int garp_pdu_parse_msg(struct garp_applicant *app, struct sk_buff *skb)
 479 {
 480         const struct garp_msg_hdr *gm;
 481 
 482         if (!pskb_may_pull(skb, sizeof(*gm)))
 483                 return -1;
 484         gm = (struct garp_msg_hdr *)skb->data;
 485         if (gm->attrtype == 0)
 486                 return -1;
 487         skb_pull(skb, sizeof(*gm));
 488 
 489         while (skb->len > 0) {
 490                 if (garp_pdu_parse_attr(app, skb, gm->attrtype) < 0)
 491                         return -1;
 492                 if (garp_pdu_parse_end_mark(skb) < 0)
 493                         break;
 494         }
 495         return 0;
 496 }
 497 
 498 static void garp_pdu_rcv(const struct stp_proto *proto, struct sk_buff *skb,
 499                          struct net_device *dev)
 500 {
 501         struct garp_application *appl = proto->data;
 502         struct garp_port *port;
 503         struct garp_applicant *app;
 504         const struct garp_pdu_hdr *gp;
 505 
 506         port = rcu_dereference(dev->garp_port);
 507         if (!port)
 508                 goto err;
 509         app = rcu_dereference(port->applicants[appl->type]);
 510         if (!app)
 511                 goto err;
 512 
 513         if (!pskb_may_pull(skb, sizeof(*gp)))
 514                 goto err;
 515         gp = (struct garp_pdu_hdr *)skb->data;
 516         if (get_unaligned(&gp->protocol) != htons(GARP_PROTOCOL_ID))
 517                 goto err;
 518         skb_pull(skb, sizeof(*gp));
 519 
 520         spin_lock(&app->lock);
 521         while (skb->len > 0) {
 522                 if (garp_pdu_parse_msg(app, skb) < 0)
 523                         break;
 524                 if (garp_pdu_parse_end_mark(skb) < 0)
 525                         break;
 526         }
 527         spin_unlock(&app->lock);
 528 err:
 529         kfree_skb(skb);
 530 }
 531 
 532 static int garp_init_port(struct net_device *dev)
 533 {
 534         struct garp_port *port;
 535 
 536         port = kzalloc(sizeof(*port), GFP_KERNEL);
 537         if (!port)
 538                 return -ENOMEM;
 539         rcu_assign_pointer(dev->garp_port, port);
 540         return 0;
 541 }
 542 
 543 static void garp_release_port(struct net_device *dev)
 544 {
 545         struct garp_port *port = rtnl_dereference(dev->garp_port);
 546         unsigned int i;
 547 
 548         for (i = 0; i <= GARP_APPLICATION_MAX; i++) {
 549                 if (rtnl_dereference(port->applicants[i]))
 550                         return;
 551         }
 552         RCU_INIT_POINTER(dev->garp_port, NULL);
 553         kfree_rcu(port, rcu);
 554 }
 555 
 556 int garp_init_applicant(struct net_device *dev, struct garp_application *appl)
 557 {
 558         struct garp_applicant *app;
 559         int err;
 560 
 561         ASSERT_RTNL();
 562 
 563         if (!rtnl_dereference(dev->garp_port)) {
 564                 err = garp_init_port(dev);
 565                 if (err < 0)
 566                         goto err1;
 567         }
 568 
 569         err = -ENOMEM;
 570         app = kzalloc(sizeof(*app), GFP_KERNEL);
 571         if (!app)
 572                 goto err2;
 573 
 574         err = dev_mc_add(dev, appl->proto.group_address);
 575         if (err < 0)
 576                 goto err3;
 577 
 578         app->dev = dev;
 579         app->app = appl;
 580         app->gid = RB_ROOT;
 581         spin_lock_init(&app->lock);
 582         skb_queue_head_init(&app->queue);
 583         rcu_assign_pointer(dev->garp_port->applicants[appl->type], app);
 584         timer_setup(&app->join_timer, garp_join_timer, 0);
 585         garp_join_timer_arm(app);
 586         return 0;
 587 
 588 err3:
 589         kfree(app);
 590 err2:
 591         garp_release_port(dev);
 592 err1:
 593         return err;
 594 }
 595 EXPORT_SYMBOL_GPL(garp_init_applicant);
 596 
 597 void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl)
 598 {
 599         struct garp_port *port = rtnl_dereference(dev->garp_port);
 600         struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
 601 
 602         ASSERT_RTNL();
 603 
 604         RCU_INIT_POINTER(port->applicants[appl->type], NULL);
 605 
 606         /* Delete timer and generate a final TRANSMIT_PDU event to flush out
 607          * all pending messages before the applicant is gone. */
 608         del_timer_sync(&app->join_timer);
 609 
 610         spin_lock_bh(&app->lock);
 611         garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU);
 612         garp_pdu_queue(app);
 613         spin_unlock_bh(&app->lock);
 614 
 615         garp_queue_xmit(app);
 616 
 617         dev_mc_del(dev, appl->proto.group_address);
 618         kfree_rcu(app, rcu);
 619         garp_release_port(dev);
 620 }
 621 EXPORT_SYMBOL_GPL(garp_uninit_applicant);
 622 
 623 int garp_register_application(struct garp_application *appl)
 624 {
 625         appl->proto.rcv = garp_pdu_rcv;
 626         appl->proto.data = appl;
 627         return stp_proto_register(&appl->proto);
 628 }
 629 EXPORT_SYMBOL_GPL(garp_register_application);
 630 
 631 void garp_unregister_application(struct garp_application *appl)
 632 {
 633         stp_proto_unregister(&appl->proto);
 634 }
 635 EXPORT_SYMBOL_GPL(garp_unregister_application);

/* [<][>][^][v][top][bottom][index][help] */