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