LCOV - code coverage report
Current view: top level - net/802 - garp.c (source / functions) Hit Total Coverage
Test: Real Lines: 4 222 1.8 %
Date: 2020-10-17 15:46:16 Functions: 0 24 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

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

Generated by: LCOV version 1.14