cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

garp.c (18245B)


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