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