Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  IEEE 802.1D Generic Attribute Registration Protocol (GARP)
0004  *
0005  *  Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
0006  */
0007 #include <linux/kernel.h>
0008 #include <linux/timer.h>
0009 #include <linux/skbuff.h>
0010 #include <linux/netdevice.h>
0011 #include <linux/etherdevice.h>
0012 #include <linux/rtnetlink.h>
0013 #include <linux/llc.h>
0014 #include <linux/slab.h>
0015 #include <linux/module.h>
0016 #include <net/llc.h>
0017 #include <net/llc_pdu.h>
0018 #include <net/garp.h>
0019 #include <asm/unaligned.h>
0020 
0021 static unsigned int garp_join_time __read_mostly = 200;
0022 module_param(garp_join_time, uint, 0644);
0023 MODULE_PARM_DESC(garp_join_time, "Join time in ms (default 200ms)");
0024 MODULE_LICENSE("GPL");
0025 
0026 static const struct garp_state_trans {
0027     u8  state;
0028     u8  action;
0029 } garp_applicant_state_table[GARP_APPLICANT_MAX + 1][GARP_EVENT_MAX + 1] = {
0030     [GARP_APPLICANT_VA] = {
0031         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_AA,
0032                             .action = GARP_ACTION_S_JOIN_IN },
0033         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_AA },
0034         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VA },
0035         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VA },
0036         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VA },
0037         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VP },
0038         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_INVALID },
0039         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_LA },
0040     },
0041     [GARP_APPLICANT_AA] = {
0042         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_QA,
0043                             .action = GARP_ACTION_S_JOIN_IN },
0044         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_QA },
0045         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VA },
0046         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VA },
0047         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VA },
0048         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VP },
0049         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_INVALID },
0050         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_LA },
0051     },
0052     [GARP_APPLICANT_QA] = {
0053         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_INVALID },
0054         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_QA },
0055         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VA },
0056         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VA },
0057         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VP },
0058         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VP },
0059         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_INVALID },
0060         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_LA },
0061     },
0062     [GARP_APPLICANT_LA] = {
0063         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_VO,
0064                             .action = GARP_ACTION_S_LEAVE_EMPTY },
0065         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_LA },
0066         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VO },
0067         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_LA },
0068         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_LA },
0069         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VO },
0070         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_VA },
0071         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_INVALID },
0072     },
0073     [GARP_APPLICANT_VP] = {
0074         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_AA,
0075                             .action = GARP_ACTION_S_JOIN_IN },
0076         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_AP },
0077         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VP },
0078         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VP },
0079         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VP },
0080         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VP },
0081         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_INVALID },
0082         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_VO },
0083     },
0084     [GARP_APPLICANT_AP] = {
0085         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_QA,
0086                             .action = GARP_ACTION_S_JOIN_IN },
0087         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_QP },
0088         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VP },
0089         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VP },
0090         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VP },
0091         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VP },
0092         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_INVALID },
0093         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_AO },
0094     },
0095     [GARP_APPLICANT_QP] = {
0096         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_INVALID },
0097         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_QP },
0098         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VP },
0099         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VP },
0100         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VP },
0101         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VP },
0102         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_INVALID },
0103         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_QO },
0104     },
0105     [GARP_APPLICANT_VO] = {
0106         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_INVALID },
0107         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_AO },
0108         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VO },
0109         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VO },
0110         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VO },
0111         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VO },
0112         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_VP },
0113         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_INVALID },
0114     },
0115     [GARP_APPLICANT_AO] = {
0116         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_INVALID },
0117         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_QO },
0118         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VO },
0119         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VO },
0120         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VO },
0121         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VO },
0122         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_AP },
0123         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_INVALID },
0124     },
0125     [GARP_APPLICANT_QO] = {
0126         [GARP_EVENT_TRANSMIT_PDU]   = { .state = GARP_APPLICANT_INVALID },
0127         [GARP_EVENT_R_JOIN_IN]      = { .state = GARP_APPLICANT_QO },
0128         [GARP_EVENT_R_JOIN_EMPTY]   = { .state = GARP_APPLICANT_VO },
0129         [GARP_EVENT_R_EMPTY]        = { .state = GARP_APPLICANT_VO },
0130         [GARP_EVENT_R_LEAVE_IN]     = { .state = GARP_APPLICANT_VO },
0131         [GARP_EVENT_R_LEAVE_EMPTY]  = { .state = GARP_APPLICANT_VO },
0132         [GARP_EVENT_REQ_JOIN]       = { .state = GARP_APPLICANT_QP },
0133         [GARP_EVENT_REQ_LEAVE]      = { .state = GARP_APPLICANT_INVALID },
0134     },
0135 };
0136 
0137 static int garp_attr_cmp(const struct garp_attr *attr,
0138              const void *data, u8 len, u8 type)
0139 {
0140     if (attr->type != type)
0141         return attr->type - type;
0142     if (attr->dlen != len)
0143         return attr->dlen - len;
0144     return memcmp(attr->data, data, len);
0145 }
0146 
0147 static struct garp_attr *garp_attr_lookup(const struct garp_applicant *app,
0148                       const void *data, u8 len, u8 type)
0149 {
0150     struct rb_node *parent = app->gid.rb_node;
0151     struct garp_attr *attr;
0152     int d;
0153 
0154     while (parent) {
0155         attr = rb_entry(parent, struct garp_attr, node);
0156         d = garp_attr_cmp(attr, data, len, type);
0157         if (d > 0)
0158             parent = parent->rb_left;
0159         else if (d < 0)
0160             parent = parent->rb_right;
0161         else
0162             return attr;
0163     }
0164     return NULL;
0165 }
0166 
0167 static struct garp_attr *garp_attr_create(struct garp_applicant *app,
0168                       const void *data, u8 len, u8 type)
0169 {
0170     struct rb_node *parent = NULL, **p = &app->gid.rb_node;
0171     struct garp_attr *attr;
0172     int d;
0173 
0174     while (*p) {
0175         parent = *p;
0176         attr = rb_entry(parent, struct garp_attr, node);
0177         d = garp_attr_cmp(attr, data, len, type);
0178         if (d > 0)
0179             p = &parent->rb_left;
0180         else if (d < 0)
0181             p = &parent->rb_right;
0182         else {
0183             /* The attribute already exists; re-use it. */
0184             return attr;
0185         }
0186     }
0187     attr = kmalloc(sizeof(*attr) + len, GFP_ATOMIC);
0188     if (!attr)
0189         return attr;
0190     attr->state = GARP_APPLICANT_VO;
0191     attr->type  = type;
0192     attr->dlen  = len;
0193     memcpy(attr->data, data, len);
0194 
0195     rb_link_node(&attr->node, parent, p);
0196     rb_insert_color(&attr->node, &app->gid);
0197     return attr;
0198 }
0199 
0200 static void garp_attr_destroy(struct garp_applicant *app, struct garp_attr *attr)
0201 {
0202     rb_erase(&attr->node, &app->gid);
0203     kfree(attr);
0204 }
0205 
0206 static void garp_attr_destroy_all(struct garp_applicant *app)
0207 {
0208     struct rb_node *node, *next;
0209     struct garp_attr *attr;
0210 
0211     for (node = rb_first(&app->gid);
0212          next = node ? rb_next(node) : NULL, node != NULL;
0213          node = next) {
0214         attr = rb_entry(node, struct garp_attr, node);
0215         garp_attr_destroy(app, attr);
0216     }
0217 }
0218 
0219 static int garp_pdu_init(struct garp_applicant *app)
0220 {
0221     struct sk_buff *skb;
0222     struct garp_pdu_hdr *gp;
0223 
0224 #define LLC_RESERVE sizeof(struct llc_pdu_un)
0225     skb = alloc_skb(app->dev->mtu + LL_RESERVED_SPACE(app->dev),
0226             GFP_ATOMIC);
0227     if (!skb)
0228         return -ENOMEM;
0229 
0230     skb->dev = app->dev;
0231     skb->protocol = htons(ETH_P_802_2);
0232     skb_reserve(skb, LL_RESERVED_SPACE(app->dev) + LLC_RESERVE);
0233 
0234     gp = __skb_put(skb, sizeof(*gp));
0235     put_unaligned(htons(GARP_PROTOCOL_ID), &gp->protocol);
0236 
0237     app->pdu = skb;
0238     return 0;
0239 }
0240 
0241 static int garp_pdu_append_end_mark(struct garp_applicant *app)
0242 {
0243     if (skb_tailroom(app->pdu) < sizeof(u8))
0244         return -1;
0245     __skb_put_u8(app->pdu, GARP_END_MARK);
0246     return 0;
0247 }
0248 
0249 static void garp_pdu_queue(struct garp_applicant *app)
0250 {
0251     if (!app->pdu)
0252         return;
0253 
0254     garp_pdu_append_end_mark(app);
0255     garp_pdu_append_end_mark(app);
0256 
0257     llc_pdu_header_init(app->pdu, LLC_PDU_TYPE_U, LLC_SAP_BSPAN,
0258                 LLC_SAP_BSPAN, LLC_PDU_CMD);
0259     llc_pdu_init_as_ui_cmd(app->pdu);
0260     llc_mac_hdr_init(app->pdu, app->dev->dev_addr,
0261              app->app->proto.group_address);
0262 
0263     skb_queue_tail(&app->queue, app->pdu);
0264     app->pdu = NULL;
0265 }
0266 
0267 static void garp_queue_xmit(struct garp_applicant *app)
0268 {
0269     struct sk_buff *skb;
0270 
0271     while ((skb = skb_dequeue(&app->queue)))
0272         dev_queue_xmit(skb);
0273 }
0274 
0275 static int garp_pdu_append_msg(struct garp_applicant *app, u8 attrtype)
0276 {
0277     struct garp_msg_hdr *gm;
0278 
0279     if (skb_tailroom(app->pdu) < sizeof(*gm))
0280         return -1;
0281     gm = __skb_put(app->pdu, sizeof(*gm));
0282     gm->attrtype = attrtype;
0283     garp_cb(app->pdu)->cur_type = attrtype;
0284     return 0;
0285 }
0286 
0287 static int garp_pdu_append_attr(struct garp_applicant *app,
0288                 const struct garp_attr *attr,
0289                 enum garp_attr_event event)
0290 {
0291     struct garp_attr_hdr *ga;
0292     unsigned int len;
0293     int err;
0294 again:
0295     if (!app->pdu) {
0296         err = garp_pdu_init(app);
0297         if (err < 0)
0298             return err;
0299     }
0300 
0301     if (garp_cb(app->pdu)->cur_type != attr->type) {
0302         if (garp_cb(app->pdu)->cur_type &&
0303             garp_pdu_append_end_mark(app) < 0)
0304             goto queue;
0305         if (garp_pdu_append_msg(app, attr->type) < 0)
0306             goto queue;
0307     }
0308 
0309     len = sizeof(*ga) + attr->dlen;
0310     if (skb_tailroom(app->pdu) < len)
0311         goto queue;
0312     ga = __skb_put(app->pdu, len);
0313     ga->len   = len;
0314     ga->event = event;
0315     memcpy(ga->data, attr->data, attr->dlen);
0316     return 0;
0317 
0318 queue:
0319     garp_pdu_queue(app);
0320     goto again;
0321 }
0322 
0323 static void garp_attr_event(struct garp_applicant *app,
0324                 struct garp_attr *attr, enum garp_event event)
0325 {
0326     enum garp_applicant_state state;
0327 
0328     state = garp_applicant_state_table[attr->state][event].state;
0329     if (state == GARP_APPLICANT_INVALID)
0330         return;
0331 
0332     switch (garp_applicant_state_table[attr->state][event].action) {
0333     case GARP_ACTION_NONE:
0334         break;
0335     case GARP_ACTION_S_JOIN_IN:
0336         /* When appending the attribute fails, don't update state in
0337          * order to retry on next TRANSMIT_PDU event. */
0338         if (garp_pdu_append_attr(app, attr, GARP_JOIN_IN) < 0)
0339             return;
0340         break;
0341     case GARP_ACTION_S_LEAVE_EMPTY:
0342         garp_pdu_append_attr(app, attr, GARP_LEAVE_EMPTY);
0343         /* As a pure applicant, sending a leave message implies that
0344          * the attribute was unregistered and can be destroyed. */
0345         garp_attr_destroy(app, attr);
0346         return;
0347     default:
0348         WARN_ON(1);
0349     }
0350 
0351     attr->state = state;
0352 }
0353 
0354 int garp_request_join(const struct net_device *dev,
0355               const struct garp_application *appl,
0356               const void *data, u8 len, u8 type)
0357 {
0358     struct garp_port *port = rtnl_dereference(dev->garp_port);
0359     struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
0360     struct garp_attr *attr;
0361 
0362     spin_lock_bh(&app->lock);
0363     attr = garp_attr_create(app, data, len, type);
0364     if (!attr) {
0365         spin_unlock_bh(&app->lock);
0366         return -ENOMEM;
0367     }
0368     garp_attr_event(app, attr, GARP_EVENT_REQ_JOIN);
0369     spin_unlock_bh(&app->lock);
0370     return 0;
0371 }
0372 EXPORT_SYMBOL_GPL(garp_request_join);
0373 
0374 void garp_request_leave(const struct net_device *dev,
0375             const struct garp_application *appl,
0376             const void *data, u8 len, u8 type)
0377 {
0378     struct garp_port *port = rtnl_dereference(dev->garp_port);
0379     struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
0380     struct garp_attr *attr;
0381 
0382     spin_lock_bh(&app->lock);
0383     attr = garp_attr_lookup(app, data, len, type);
0384     if (!attr) {
0385         spin_unlock_bh(&app->lock);
0386         return;
0387     }
0388     garp_attr_event(app, attr, GARP_EVENT_REQ_LEAVE);
0389     spin_unlock_bh(&app->lock);
0390 }
0391 EXPORT_SYMBOL_GPL(garp_request_leave);
0392 
0393 static void garp_gid_event(struct garp_applicant *app, enum garp_event event)
0394 {
0395     struct rb_node *node, *next;
0396     struct garp_attr *attr;
0397 
0398     for (node = rb_first(&app->gid);
0399          next = node ? rb_next(node) : NULL, node != NULL;
0400          node = next) {
0401         attr = rb_entry(node, struct garp_attr, node);
0402         garp_attr_event(app, attr, event);
0403     }
0404 }
0405 
0406 static void garp_join_timer_arm(struct garp_applicant *app)
0407 {
0408     unsigned long delay;
0409 
0410     delay = (u64)msecs_to_jiffies(garp_join_time) * prandom_u32() >> 32;
0411     mod_timer(&app->join_timer, jiffies + delay);
0412 }
0413 
0414 static void garp_join_timer(struct timer_list *t)
0415 {
0416     struct garp_applicant *app = from_timer(app, t, join_timer);
0417 
0418     spin_lock(&app->lock);
0419     garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU);
0420     garp_pdu_queue(app);
0421     spin_unlock(&app->lock);
0422 
0423     garp_queue_xmit(app);
0424     garp_join_timer_arm(app);
0425 }
0426 
0427 static int garp_pdu_parse_end_mark(struct sk_buff *skb)
0428 {
0429     if (!pskb_may_pull(skb, sizeof(u8)))
0430         return -1;
0431     if (*skb->data == GARP_END_MARK) {
0432         skb_pull(skb, sizeof(u8));
0433         return -1;
0434     }
0435     return 0;
0436 }
0437 
0438 static int garp_pdu_parse_attr(struct garp_applicant *app, struct sk_buff *skb,
0439                    u8 attrtype)
0440 {
0441     const struct garp_attr_hdr *ga;
0442     struct garp_attr *attr;
0443     enum garp_event event;
0444     unsigned int dlen;
0445 
0446     if (!pskb_may_pull(skb, sizeof(*ga)))
0447         return -1;
0448     ga = (struct garp_attr_hdr *)skb->data;
0449     if (ga->len < sizeof(*ga))
0450         return -1;
0451 
0452     if (!pskb_may_pull(skb, ga->len))
0453         return -1;
0454     skb_pull(skb, ga->len);
0455     dlen = sizeof(*ga) - ga->len;
0456 
0457     if (attrtype > app->app->maxattr)
0458         return 0;
0459 
0460     switch (ga->event) {
0461     case GARP_LEAVE_ALL:
0462         if (dlen != 0)
0463             return -1;
0464         garp_gid_event(app, GARP_EVENT_R_LEAVE_EMPTY);
0465         return 0;
0466     case GARP_JOIN_EMPTY:
0467         event = GARP_EVENT_R_JOIN_EMPTY;
0468         break;
0469     case GARP_JOIN_IN:
0470         event = GARP_EVENT_R_JOIN_IN;
0471         break;
0472     case GARP_LEAVE_EMPTY:
0473         event = GARP_EVENT_R_LEAVE_EMPTY;
0474         break;
0475     case GARP_EMPTY:
0476         event = GARP_EVENT_R_EMPTY;
0477         break;
0478     default:
0479         return 0;
0480     }
0481 
0482     if (dlen == 0)
0483         return -1;
0484     attr = garp_attr_lookup(app, ga->data, dlen, attrtype);
0485     if (attr == NULL)
0486         return 0;
0487     garp_attr_event(app, attr, event);
0488     return 0;
0489 }
0490 
0491 static int garp_pdu_parse_msg(struct garp_applicant *app, struct sk_buff *skb)
0492 {
0493     const struct garp_msg_hdr *gm;
0494 
0495     if (!pskb_may_pull(skb, sizeof(*gm)))
0496         return -1;
0497     gm = (struct garp_msg_hdr *)skb->data;
0498     if (gm->attrtype == 0)
0499         return -1;
0500     skb_pull(skb, sizeof(*gm));
0501 
0502     while (skb->len > 0) {
0503         if (garp_pdu_parse_attr(app, skb, gm->attrtype) < 0)
0504             return -1;
0505         if (garp_pdu_parse_end_mark(skb) < 0)
0506             break;
0507     }
0508     return 0;
0509 }
0510 
0511 static void garp_pdu_rcv(const struct stp_proto *proto, struct sk_buff *skb,
0512              struct net_device *dev)
0513 {
0514     struct garp_application *appl = proto->data;
0515     struct garp_port *port;
0516     struct garp_applicant *app;
0517     const struct garp_pdu_hdr *gp;
0518 
0519     port = rcu_dereference(dev->garp_port);
0520     if (!port)
0521         goto err;
0522     app = rcu_dereference(port->applicants[appl->type]);
0523     if (!app)
0524         goto err;
0525 
0526     if (!pskb_may_pull(skb, sizeof(*gp)))
0527         goto err;
0528     gp = (struct garp_pdu_hdr *)skb->data;
0529     if (get_unaligned(&gp->protocol) != htons(GARP_PROTOCOL_ID))
0530         goto err;
0531     skb_pull(skb, sizeof(*gp));
0532 
0533     spin_lock(&app->lock);
0534     while (skb->len > 0) {
0535         if (garp_pdu_parse_msg(app, skb) < 0)
0536             break;
0537         if (garp_pdu_parse_end_mark(skb) < 0)
0538             break;
0539     }
0540     spin_unlock(&app->lock);
0541 err:
0542     kfree_skb(skb);
0543 }
0544 
0545 static int garp_init_port(struct net_device *dev)
0546 {
0547     struct garp_port *port;
0548 
0549     port = kzalloc(sizeof(*port), GFP_KERNEL);
0550     if (!port)
0551         return -ENOMEM;
0552     rcu_assign_pointer(dev->garp_port, port);
0553     return 0;
0554 }
0555 
0556 static void garp_release_port(struct net_device *dev)
0557 {
0558     struct garp_port *port = rtnl_dereference(dev->garp_port);
0559     unsigned int i;
0560 
0561     for (i = 0; i <= GARP_APPLICATION_MAX; i++) {
0562         if (rtnl_dereference(port->applicants[i]))
0563             return;
0564     }
0565     RCU_INIT_POINTER(dev->garp_port, NULL);
0566     kfree_rcu(port, rcu);
0567 }
0568 
0569 int garp_init_applicant(struct net_device *dev, struct garp_application *appl)
0570 {
0571     struct garp_applicant *app;
0572     int err;
0573 
0574     ASSERT_RTNL();
0575 
0576     if (!rtnl_dereference(dev->garp_port)) {
0577         err = garp_init_port(dev);
0578         if (err < 0)
0579             goto err1;
0580     }
0581 
0582     err = -ENOMEM;
0583     app = kzalloc(sizeof(*app), GFP_KERNEL);
0584     if (!app)
0585         goto err2;
0586 
0587     err = dev_mc_add(dev, appl->proto.group_address);
0588     if (err < 0)
0589         goto err3;
0590 
0591     app->dev = dev;
0592     app->app = appl;
0593     app->gid = RB_ROOT;
0594     spin_lock_init(&app->lock);
0595     skb_queue_head_init(&app->queue);
0596     rcu_assign_pointer(dev->garp_port->applicants[appl->type], app);
0597     timer_setup(&app->join_timer, garp_join_timer, 0);
0598     garp_join_timer_arm(app);
0599     return 0;
0600 
0601 err3:
0602     kfree(app);
0603 err2:
0604     garp_release_port(dev);
0605 err1:
0606     return err;
0607 }
0608 EXPORT_SYMBOL_GPL(garp_init_applicant);
0609 
0610 void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl)
0611 {
0612     struct garp_port *port = rtnl_dereference(dev->garp_port);
0613     struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
0614 
0615     ASSERT_RTNL();
0616 
0617     RCU_INIT_POINTER(port->applicants[appl->type], NULL);
0618 
0619     /* Delete timer and generate a final TRANSMIT_PDU event to flush out
0620      * all pending messages before the applicant is gone. */
0621     del_timer_sync(&app->join_timer);
0622 
0623     spin_lock_bh(&app->lock);
0624     garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU);
0625     garp_attr_destroy_all(app);
0626     garp_pdu_queue(app);
0627     spin_unlock_bh(&app->lock);
0628 
0629     garp_queue_xmit(app);
0630 
0631     dev_mc_del(dev, appl->proto.group_address);
0632     kfree_rcu(app, rcu);
0633     garp_release_port(dev);
0634 }
0635 EXPORT_SYMBOL_GPL(garp_uninit_applicant);
0636 
0637 int garp_register_application(struct garp_application *appl)
0638 {
0639     appl->proto.rcv = garp_pdu_rcv;
0640     appl->proto.data = appl;
0641     return stp_proto_register(&appl->proto);
0642 }
0643 EXPORT_SYMBOL_GPL(garp_register_application);
0644 
0645 void garp_unregister_application(struct garp_application *appl)
0646 {
0647     stp_proto_unregister(&appl->proto);
0648 }
0649 EXPORT_SYMBOL_GPL(garp_unregister_application);