root/net/llc/llc_sap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. llc_mac_header_len
  2. llc_alloc_frame
  3. llc_save_primitive
  4. llc_sap_rtn_pdu
  5. llc_find_sap_trans
  6. llc_exec_sap_trans_actions
  7. llc_sap_next_state
  8. llc_sap_state_process
  9. llc_build_and_send_test_pkt
  10. llc_build_and_send_xid_pkt
  11. llc_sap_rcv
  12. llc_dgram_match
  13. llc_lookup_dgram
  14. llc_mcast_match
  15. llc_do_mcast
  16. llc_sap_mcast
  17. llc_sap_handler

   1 /*
   2  * llc_sap.c - driver routines for SAP component.
   3  *
   4  * Copyright (c) 1997 by Procom Technology, Inc.
   5  *               2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   6  *
   7  * This program can be redistributed or modified under the terms of the
   8  * GNU General Public License as published by the Free Software Foundation.
   9  * This program is distributed without any warranty or implied warranty
  10  * of merchantability or fitness for a particular purpose.
  11  *
  12  * See the GNU General Public License for more details.
  13  */
  14 
  15 #include <net/llc.h>
  16 #include <net/llc_if.h>
  17 #include <net/llc_conn.h>
  18 #include <net/llc_pdu.h>
  19 #include <net/llc_sap.h>
  20 #include <net/llc_s_ac.h>
  21 #include <net/llc_s_ev.h>
  22 #include <net/llc_s_st.h>
  23 #include <net/sock.h>
  24 #include <net/tcp_states.h>
  25 #include <linux/llc.h>
  26 #include <linux/slab.h>
  27 
  28 static int llc_mac_header_len(unsigned short devtype)
  29 {
  30         switch (devtype) {
  31         case ARPHRD_ETHER:
  32         case ARPHRD_LOOPBACK:
  33                 return sizeof(struct ethhdr);
  34         }
  35         return 0;
  36 }
  37 
  38 /**
  39  *      llc_alloc_frame - allocates sk_buff for frame
  40  *      @dev: network device this skb will be sent over
  41  *      @type: pdu type to allocate
  42  *      @data_size: data size to allocate
  43  *
  44  *      Allocates an sk_buff for frame and initializes sk_buff fields.
  45  *      Returns allocated skb or %NULL when out of memory.
  46  */
  47 struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev,
  48                                 u8 type, u32 data_size)
  49 {
  50         int hlen = type == LLC_PDU_TYPE_U ? 3 : 4;
  51         struct sk_buff *skb;
  52 
  53         hlen += llc_mac_header_len(dev->type);
  54         skb = alloc_skb(hlen + data_size, GFP_ATOMIC);
  55 
  56         if (skb) {
  57                 skb_reset_mac_header(skb);
  58                 skb_reserve(skb, hlen);
  59                 skb_reset_network_header(skb);
  60                 skb_reset_transport_header(skb);
  61                 skb->protocol = htons(ETH_P_802_2);
  62                 skb->dev      = dev;
  63                 if (sk != NULL)
  64                         skb_set_owner_w(skb, sk);
  65         }
  66         return skb;
  67 }
  68 
  69 void llc_save_primitive(struct sock *sk, struct sk_buff *skb, u8 prim)
  70 {
  71         struct sockaddr_llc *addr;
  72 
  73        /* save primitive for use by the user. */
  74         addr              = llc_ui_skb_cb(skb);
  75 
  76         memset(addr, 0, sizeof(*addr));
  77         addr->sllc_family = sk->sk_family;
  78         addr->sllc_arphrd = skb->dev->type;
  79         addr->sllc_test   = prim == LLC_TEST_PRIM;
  80         addr->sllc_xid    = prim == LLC_XID_PRIM;
  81         addr->sllc_ua     = prim == LLC_DATAUNIT_PRIM;
  82         llc_pdu_decode_sa(skb, addr->sllc_mac);
  83         llc_pdu_decode_ssap(skb, &addr->sllc_sap);
  84 }
  85 
  86 /**
  87  *      llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu.
  88  *      @sap: pointer to SAP
  89  *      @skb: received pdu
  90  */
  91 void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb)
  92 {
  93         struct llc_sap_state_ev *ev = llc_sap_ev(skb);
  94         struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
  95 
  96         switch (LLC_U_PDU_RSP(pdu)) {
  97         case LLC_1_PDU_CMD_TEST:
  98                 ev->prim = LLC_TEST_PRIM;       break;
  99         case LLC_1_PDU_CMD_XID:
 100                 ev->prim = LLC_XID_PRIM;        break;
 101         case LLC_1_PDU_CMD_UI:
 102                 ev->prim = LLC_DATAUNIT_PRIM;   break;
 103         }
 104         ev->ind_cfm_flag = LLC_IND;
 105 }
 106 
 107 /**
 108  *      llc_find_sap_trans - finds transition for event
 109  *      @sap: pointer to SAP
 110  *      @skb: happened event
 111  *
 112  *      This function finds transition that matches with happened event.
 113  *      Returns the pointer to found transition on success or %NULL for
 114  *      failure.
 115  */
 116 static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
 117                                                       struct sk_buff *skb)
 118 {
 119         int i = 0;
 120         struct llc_sap_state_trans *rc = NULL;
 121         struct llc_sap_state_trans **next_trans;
 122         struct llc_sap_state *curr_state = &llc_sap_state_table[sap->state - 1];
 123         /*
 124          * Search thru events for this state until list exhausted or until
 125          * its obvious the event is not valid for the current state
 126          */
 127         for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
 128                 if (!next_trans[i]->ev(sap, skb)) {
 129                         rc = next_trans[i]; /* got event match; return it */
 130                         break;
 131                 }
 132         return rc;
 133 }
 134 
 135 /**
 136  *      llc_exec_sap_trans_actions - execute actions related to event
 137  *      @sap: pointer to SAP
 138  *      @trans: pointer to transition that it's actions must be performed
 139  *      @skb: happened event.
 140  *
 141  *      This function executes actions that is related to happened event.
 142  *      Returns 0 for success and 1 for failure of at least one action.
 143  */
 144 static int llc_exec_sap_trans_actions(struct llc_sap *sap,
 145                                       struct llc_sap_state_trans *trans,
 146                                       struct sk_buff *skb)
 147 {
 148         int rc = 0;
 149         const llc_sap_action_t *next_action = trans->ev_actions;
 150 
 151         for (; next_action && *next_action; next_action++)
 152                 if ((*next_action)(sap, skb))
 153                         rc = 1;
 154         return rc;
 155 }
 156 
 157 /**
 158  *      llc_sap_next_state - finds transition, execs actions & change SAP state
 159  *      @sap: pointer to SAP
 160  *      @skb: happened event
 161  *
 162  *      This function finds transition that matches with happened event, then
 163  *      executes related actions and finally changes state of SAP. It returns
 164  *      0 on success and 1 for failure.
 165  */
 166 static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb)
 167 {
 168         int rc = 1;
 169         struct llc_sap_state_trans *trans;
 170 
 171         if (sap->state > LLC_NR_SAP_STATES)
 172                 goto out;
 173         trans = llc_find_sap_trans(sap, skb);
 174         if (!trans)
 175                 goto out;
 176         /*
 177          * Got the state to which we next transition; perform the actions
 178          * associated with this transition before actually transitioning to the
 179          * next state
 180          */
 181         rc = llc_exec_sap_trans_actions(sap, trans, skb);
 182         if (rc)
 183                 goto out;
 184         /*
 185          * Transition SAP to next state if all actions execute successfully
 186          */
 187         sap->state = trans->next_state;
 188 out:
 189         return rc;
 190 }
 191 
 192 /**
 193  *      llc_sap_state_process - sends event to SAP state machine
 194  *      @sap: sap to use
 195  *      @skb: pointer to occurred event
 196  *
 197  *      After executing actions of the event, upper layer will be indicated
 198  *      if needed(on receiving an UI frame). sk can be null for the
 199  *      datalink_proto case.
 200  *
 201  *      This function always consumes a reference to the skb.
 202  */
 203 static void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
 204 {
 205         struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 206 
 207         ev->ind_cfm_flag = 0;
 208         llc_sap_next_state(sap, skb);
 209 
 210         if (ev->ind_cfm_flag == LLC_IND && skb->sk->sk_state != TCP_LISTEN) {
 211                 llc_save_primitive(skb->sk, skb, ev->prim);
 212 
 213                 /* queue skb to the user. */
 214                 if (sock_queue_rcv_skb(skb->sk, skb) == 0)
 215                         return;
 216         }
 217         kfree_skb(skb);
 218 }
 219 
 220 /**
 221  *      llc_build_and_send_test_pkt - TEST interface for upper layers.
 222  *      @sap: sap to use
 223  *      @skb: packet to send
 224  *      @dmac: destination mac address
 225  *      @dsap: destination sap
 226  *
 227  *      This function is called when upper layer wants to send a TEST pdu.
 228  *      Returns 0 for success, 1 otherwise.
 229  */
 230 void llc_build_and_send_test_pkt(struct llc_sap *sap,
 231                                  struct sk_buff *skb, u8 *dmac, u8 dsap)
 232 {
 233         struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 234 
 235         ev->saddr.lsap = sap->laddr.lsap;
 236         ev->daddr.lsap = dsap;
 237         memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
 238         memcpy(ev->daddr.mac, dmac, IFHWADDRLEN);
 239 
 240         ev->type      = LLC_SAP_EV_TYPE_PRIM;
 241         ev->prim      = LLC_TEST_PRIM;
 242         ev->prim_type = LLC_PRIM_TYPE_REQ;
 243         llc_sap_state_process(sap, skb);
 244 }
 245 
 246 /**
 247  *      llc_build_and_send_xid_pkt - XID interface for upper layers
 248  *      @sap: sap to use
 249  *      @skb: packet to send
 250  *      @dmac: destination mac address
 251  *      @dsap: destination sap
 252  *
 253  *      This function is called when upper layer wants to send a XID pdu.
 254  *      Returns 0 for success, 1 otherwise.
 255  */
 256 void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
 257                                 u8 *dmac, u8 dsap)
 258 {
 259         struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 260 
 261         ev->saddr.lsap = sap->laddr.lsap;
 262         ev->daddr.lsap = dsap;
 263         memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
 264         memcpy(ev->daddr.mac, dmac, IFHWADDRLEN);
 265 
 266         ev->type      = LLC_SAP_EV_TYPE_PRIM;
 267         ev->prim      = LLC_XID_PRIM;
 268         ev->prim_type = LLC_PRIM_TYPE_REQ;
 269         llc_sap_state_process(sap, skb);
 270 }
 271 
 272 /**
 273  *      llc_sap_rcv - sends received pdus to the sap state machine
 274  *      @sap: current sap component structure.
 275  *      @skb: received frame.
 276  *
 277  *      Sends received pdus to the sap state machine.
 278  */
 279 static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
 280                         struct sock *sk)
 281 {
 282         struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 283 
 284         ev->type   = LLC_SAP_EV_TYPE_PDU;
 285         ev->reason = 0;
 286         skb_orphan(skb);
 287         sock_hold(sk);
 288         skb->sk = sk;
 289         skb->destructor = sock_efree;
 290         llc_sap_state_process(sap, skb);
 291 }
 292 
 293 static inline bool llc_dgram_match(const struct llc_sap *sap,
 294                                    const struct llc_addr *laddr,
 295                                    const struct sock *sk)
 296 {
 297      struct llc_sock *llc = llc_sk(sk);
 298 
 299      return sk->sk_type == SOCK_DGRAM &&
 300           llc->laddr.lsap == laddr->lsap &&
 301           ether_addr_equal(llc->laddr.mac, laddr->mac);
 302 }
 303 
 304 /**
 305  *      llc_lookup_dgram - Finds dgram socket for the local sap/mac
 306  *      @sap: SAP
 307  *      @laddr: address of local LLC (MAC + SAP)
 308  *
 309  *      Search socket list of the SAP and finds connection using the local
 310  *      mac, and local sap. Returns pointer for socket found, %NULL otherwise.
 311  */
 312 static struct sock *llc_lookup_dgram(struct llc_sap *sap,
 313                                      const struct llc_addr *laddr)
 314 {
 315         struct sock *rc;
 316         struct hlist_nulls_node *node;
 317         int slot = llc_sk_laddr_hashfn(sap, laddr);
 318         struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
 319 
 320         rcu_read_lock_bh();
 321 again:
 322         sk_nulls_for_each_rcu(rc, node, laddr_hb) {
 323                 if (llc_dgram_match(sap, laddr, rc)) {
 324                         /* Extra checks required by SLAB_TYPESAFE_BY_RCU */
 325                         if (unlikely(!refcount_inc_not_zero(&rc->sk_refcnt)))
 326                                 goto again;
 327                         if (unlikely(llc_sk(rc)->sap != sap ||
 328                                      !llc_dgram_match(sap, laddr, rc))) {
 329                                 sock_put(rc);
 330                                 continue;
 331                         }
 332                         goto found;
 333                 }
 334         }
 335         rc = NULL;
 336         /*
 337          * if the nulls value we got at the end of this lookup is
 338          * not the expected one, we must restart lookup.
 339          * We probably met an item that was moved to another chain.
 340          */
 341         if (unlikely(get_nulls_value(node) != slot))
 342                 goto again;
 343 found:
 344         rcu_read_unlock_bh();
 345         return rc;
 346 }
 347 
 348 static inline bool llc_mcast_match(const struct llc_sap *sap,
 349                                    const struct llc_addr *laddr,
 350                                    const struct sk_buff *skb,
 351                                    const struct sock *sk)
 352 {
 353      struct llc_sock *llc = llc_sk(sk);
 354 
 355      return sk->sk_type == SOCK_DGRAM &&
 356           llc->laddr.lsap == laddr->lsap &&
 357           llc->dev == skb->dev;
 358 }
 359 
 360 static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb,
 361                          struct sock **stack, int count)
 362 {
 363         struct sk_buff *skb1;
 364         int i;
 365 
 366         for (i = 0; i < count; i++) {
 367                 skb1 = skb_clone(skb, GFP_ATOMIC);
 368                 if (!skb1) {
 369                         sock_put(stack[i]);
 370                         continue;
 371                 }
 372 
 373                 llc_sap_rcv(sap, skb1, stack[i]);
 374                 sock_put(stack[i]);
 375         }
 376 }
 377 
 378 /**
 379  *      llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
 380  *      @sap: SAP
 381  *      @laddr: address of local LLC (MAC + SAP)
 382  *
 383  *      Search socket list of the SAP and finds connections with same sap.
 384  *      Deliver clone to each.
 385  */
 386 static void llc_sap_mcast(struct llc_sap *sap,
 387                           const struct llc_addr *laddr,
 388                           struct sk_buff *skb)
 389 {
 390         int i = 0;
 391         struct sock *sk;
 392         struct sock *stack[256 / sizeof(struct sock *)];
 393         struct llc_sock *llc;
 394         struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex);
 395 
 396         spin_lock_bh(&sap->sk_lock);
 397         hlist_for_each_entry(llc, dev_hb, dev_hash_node) {
 398 
 399                 sk = &llc->sk;
 400 
 401                 if (!llc_mcast_match(sap, laddr, skb, sk))
 402                         continue;
 403 
 404                 sock_hold(sk);
 405                 if (i < ARRAY_SIZE(stack))
 406                         stack[i++] = sk;
 407                 else {
 408                         llc_do_mcast(sap, skb, stack, i);
 409                         i = 0;
 410                 }
 411         }
 412         spin_unlock_bh(&sap->sk_lock);
 413 
 414         llc_do_mcast(sap, skb, stack, i);
 415 }
 416 
 417 
 418 void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb)
 419 {
 420         struct llc_addr laddr;
 421 
 422         llc_pdu_decode_da(skb, laddr.mac);
 423         llc_pdu_decode_dsap(skb, &laddr.lsap);
 424 
 425         if (is_multicast_ether_addr(laddr.mac)) {
 426                 llc_sap_mcast(sap, &laddr, skb);
 427                 kfree_skb(skb);
 428         } else {
 429                 struct sock *sk = llc_lookup_dgram(sap, &laddr);
 430                 if (sk) {
 431                         llc_sap_rcv(sap, skb, sk);
 432                         sock_put(sk);
 433                 } else
 434                         kfree_skb(skb);
 435         }
 436 }

/* [<][>][^][v][top][bottom][index][help] */