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