Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * llc_sap.c - driver routines for SAP component.
0003  *
0004  * Copyright (c) 1997 by Procom Technology, Inc.
0005  *       2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
0006  *
0007  * This program can be redistributed or modified under the terms of the
0008  * GNU General Public License as published by the Free Software Foundation.
0009  * This program is distributed without any warranty or implied warranty
0010  * of merchantability or fitness for a particular purpose.
0011  *
0012  * See the GNU General Public License for more details.
0013  */
0014 
0015 #include <net/llc.h>
0016 #include <net/llc_if.h>
0017 #include <net/llc_conn.h>
0018 #include <net/llc_pdu.h>
0019 #include <net/llc_sap.h>
0020 #include <net/llc_s_ac.h>
0021 #include <net/llc_s_ev.h>
0022 #include <net/llc_s_st.h>
0023 #include <net/sock.h>
0024 #include <net/tcp_states.h>
0025 #include <linux/llc.h>
0026 #include <linux/slab.h>
0027 
0028 static int llc_mac_header_len(unsigned short devtype)
0029 {
0030     switch (devtype) {
0031     case ARPHRD_ETHER:
0032     case ARPHRD_LOOPBACK:
0033         return sizeof(struct ethhdr);
0034     }
0035     return 0;
0036 }
0037 
0038 /**
0039  *  llc_alloc_frame - allocates sk_buff for frame
0040  *  @sk:  socket to allocate frame to
0041  *  @dev: network device this skb will be sent over
0042  *  @type: pdu type to allocate
0043  *  @data_size: data size to allocate
0044  *
0045  *  Allocates an sk_buff for frame and initializes sk_buff fields.
0046  *  Returns allocated skb or %NULL when out of memory.
0047  */
0048 struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev,
0049                 u8 type, u32 data_size)
0050 {
0051     int hlen = type == LLC_PDU_TYPE_U ? 3 : 4;
0052     struct sk_buff *skb;
0053 
0054     hlen += llc_mac_header_len(dev->type);
0055     skb = alloc_skb(hlen + data_size, GFP_ATOMIC);
0056 
0057     if (skb) {
0058         skb_reset_mac_header(skb);
0059         skb_reserve(skb, hlen);
0060         skb_reset_network_header(skb);
0061         skb_reset_transport_header(skb);
0062         skb->protocol = htons(ETH_P_802_2);
0063         skb->dev      = dev;
0064         if (sk != NULL)
0065             skb_set_owner_w(skb, sk);
0066     }
0067     return skb;
0068 }
0069 
0070 void llc_save_primitive(struct sock *sk, struct sk_buff *skb, u8 prim)
0071 {
0072     struct sockaddr_llc *addr;
0073 
0074        /* save primitive for use by the user. */
0075     addr          = llc_ui_skb_cb(skb);
0076 
0077     memset(addr, 0, sizeof(*addr));
0078     addr->sllc_family = sk->sk_family;
0079     addr->sllc_arphrd = skb->dev->type;
0080     addr->sllc_test   = prim == LLC_TEST_PRIM;
0081     addr->sllc_xid    = prim == LLC_XID_PRIM;
0082     addr->sllc_ua     = prim == LLC_DATAUNIT_PRIM;
0083     llc_pdu_decode_sa(skb, addr->sllc_mac);
0084     llc_pdu_decode_ssap(skb, &addr->sllc_sap);
0085 }
0086 
0087 /**
0088  *  llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu.
0089  *  @sap: pointer to SAP
0090  *  @skb: received pdu
0091  */
0092 void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb)
0093 {
0094     struct llc_sap_state_ev *ev = llc_sap_ev(skb);
0095     struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0096 
0097     switch (LLC_U_PDU_RSP(pdu)) {
0098     case LLC_1_PDU_CMD_TEST:
0099         ev->prim = LLC_TEST_PRIM;   break;
0100     case LLC_1_PDU_CMD_XID:
0101         ev->prim = LLC_XID_PRIM;    break;
0102     case LLC_1_PDU_CMD_UI:
0103         ev->prim = LLC_DATAUNIT_PRIM;   break;
0104     }
0105     ev->ind_cfm_flag = LLC_IND;
0106 }
0107 
0108 /**
0109  *  llc_find_sap_trans - finds transition for event
0110  *  @sap: pointer to SAP
0111  *  @skb: happened event
0112  *
0113  *  This function finds transition that matches with happened event.
0114  *  Returns the pointer to found transition on success or %NULL for
0115  *  failure.
0116  */
0117 static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
0118                               struct sk_buff *skb)
0119 {
0120     int i = 0;
0121     struct llc_sap_state_trans *rc = NULL;
0122     struct llc_sap_state_trans **next_trans;
0123     struct llc_sap_state *curr_state = &llc_sap_state_table[sap->state - 1];
0124     /*
0125      * Search thru events for this state until list exhausted or until
0126      * its obvious the event is not valid for the current state
0127      */
0128     for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
0129         if (!next_trans[i]->ev(sap, skb)) {
0130             rc = next_trans[i]; /* got event match; return it */
0131             break;
0132         }
0133     return rc;
0134 }
0135 
0136 /**
0137  *  llc_exec_sap_trans_actions - execute actions related to event
0138  *  @sap: pointer to SAP
0139  *  @trans: pointer to transition that it's actions must be performed
0140  *  @skb: happened event.
0141  *
0142  *  This function executes actions that is related to happened event.
0143  *  Returns 0 for success and 1 for failure of at least one action.
0144  */
0145 static int llc_exec_sap_trans_actions(struct llc_sap *sap,
0146                       struct llc_sap_state_trans *trans,
0147                       struct sk_buff *skb)
0148 {
0149     int rc = 0;
0150     const llc_sap_action_t *next_action = trans->ev_actions;
0151 
0152     for (; next_action && *next_action; next_action++)
0153         if ((*next_action)(sap, skb))
0154             rc = 1;
0155     return rc;
0156 }
0157 
0158 /**
0159  *  llc_sap_next_state - finds transition, execs actions & change SAP state
0160  *  @sap: pointer to SAP
0161  *  @skb: happened event
0162  *
0163  *  This function finds transition that matches with happened event, then
0164  *  executes related actions and finally changes state of SAP. It returns
0165  *  0 on success and 1 for failure.
0166  */
0167 static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb)
0168 {
0169     int rc = 1;
0170     struct llc_sap_state_trans *trans;
0171 
0172     if (sap->state > LLC_NR_SAP_STATES)
0173         goto out;
0174     trans = llc_find_sap_trans(sap, skb);
0175     if (!trans)
0176         goto out;
0177     /*
0178      * Got the state to which we next transition; perform the actions
0179      * associated with this transition before actually transitioning to the
0180      * next state
0181      */
0182     rc = llc_exec_sap_trans_actions(sap, trans, skb);
0183     if (rc)
0184         goto out;
0185     /*
0186      * Transition SAP to next state if all actions execute successfully
0187      */
0188     sap->state = trans->next_state;
0189 out:
0190     return rc;
0191 }
0192 
0193 /**
0194  *  llc_sap_state_process - sends event to SAP state machine
0195  *  @sap: sap to use
0196  *  @skb: pointer to occurred event
0197  *
0198  *  After executing actions of the event, upper layer will be indicated
0199  *  if needed(on receiving an UI frame). sk can be null for the
0200  *  datalink_proto case.
0201  *
0202  *  This function always consumes a reference to the skb.
0203  */
0204 static void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
0205 {
0206     struct llc_sap_state_ev *ev = llc_sap_ev(skb);
0207 
0208     ev->ind_cfm_flag = 0;
0209     llc_sap_next_state(sap, skb);
0210 
0211     if (ev->ind_cfm_flag == LLC_IND && skb->sk->sk_state != TCP_LISTEN) {
0212         llc_save_primitive(skb->sk, skb, ev->prim);
0213 
0214         /* queue skb to the user. */
0215         if (sock_queue_rcv_skb(skb->sk, skb) == 0)
0216             return;
0217     }
0218     kfree_skb(skb);
0219 }
0220 
0221 /**
0222  *  llc_build_and_send_test_pkt - TEST interface for upper layers.
0223  *  @sap: sap to use
0224  *  @skb: packet to send
0225  *  @dmac: destination mac address
0226  *  @dsap: destination sap
0227  *
0228  *  This function is called when upper layer wants to send a TEST pdu.
0229  *  Returns 0 for success, 1 otherwise.
0230  */
0231 void llc_build_and_send_test_pkt(struct llc_sap *sap,
0232                  struct sk_buff *skb, u8 *dmac, u8 dsap)
0233 {
0234     struct llc_sap_state_ev *ev = llc_sap_ev(skb);
0235 
0236     ev->saddr.lsap = sap->laddr.lsap;
0237     ev->daddr.lsap = dsap;
0238     memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
0239     memcpy(ev->daddr.mac, dmac, IFHWADDRLEN);
0240 
0241     ev->type      = LLC_SAP_EV_TYPE_PRIM;
0242     ev->prim      = LLC_TEST_PRIM;
0243     ev->prim_type = LLC_PRIM_TYPE_REQ;
0244     llc_sap_state_process(sap, skb);
0245 }
0246 
0247 /**
0248  *  llc_build_and_send_xid_pkt - XID interface for upper layers
0249  *  @sap: sap to use
0250  *  @skb: packet to send
0251  *  @dmac: destination mac address
0252  *  @dsap: destination sap
0253  *
0254  *  This function is called when upper layer wants to send a XID pdu.
0255  *  Returns 0 for success, 1 otherwise.
0256  */
0257 void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
0258                 u8 *dmac, u8 dsap)
0259 {
0260     struct llc_sap_state_ev *ev = llc_sap_ev(skb);
0261 
0262     ev->saddr.lsap = sap->laddr.lsap;
0263     ev->daddr.lsap = dsap;
0264     memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
0265     memcpy(ev->daddr.mac, dmac, IFHWADDRLEN);
0266 
0267     ev->type      = LLC_SAP_EV_TYPE_PRIM;
0268     ev->prim      = LLC_XID_PRIM;
0269     ev->prim_type = LLC_PRIM_TYPE_REQ;
0270     llc_sap_state_process(sap, skb);
0271 }
0272 
0273 /**
0274  *  llc_sap_rcv - sends received pdus to the sap state machine
0275  *  @sap: current sap component structure.
0276  *  @skb: received frame.
0277  *  @sk:  socket to associate to frame
0278  *
0279  *  Sends received pdus to the sap state machine.
0280  */
0281 static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
0282             struct sock *sk)
0283 {
0284     struct llc_sap_state_ev *ev = llc_sap_ev(skb);
0285 
0286     ev->type   = LLC_SAP_EV_TYPE_PDU;
0287     ev->reason = 0;
0288     skb_orphan(skb);
0289     sock_hold(sk);
0290     skb->sk = sk;
0291     skb->destructor = sock_efree;
0292     llc_sap_state_process(sap, skb);
0293 }
0294 
0295 static inline bool llc_dgram_match(const struct llc_sap *sap,
0296                    const struct llc_addr *laddr,
0297                    const struct sock *sk)
0298 {
0299      struct llc_sock *llc = llc_sk(sk);
0300 
0301      return sk->sk_type == SOCK_DGRAM &&
0302       llc->laddr.lsap == laddr->lsap &&
0303       ether_addr_equal(llc->laddr.mac, laddr->mac);
0304 }
0305 
0306 /**
0307  *  llc_lookup_dgram - Finds dgram socket for the local sap/mac
0308  *  @sap: SAP
0309  *  @laddr: address of local LLC (MAC + SAP)
0310  *
0311  *  Search socket list of the SAP and finds connection using the local
0312  *  mac, and local sap. Returns pointer for socket found, %NULL otherwise.
0313  */
0314 static struct sock *llc_lookup_dgram(struct llc_sap *sap,
0315                      const struct llc_addr *laddr)
0316 {
0317     struct sock *rc;
0318     struct hlist_nulls_node *node;
0319     int slot = llc_sk_laddr_hashfn(sap, laddr);
0320     struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
0321 
0322     rcu_read_lock_bh();
0323 again:
0324     sk_nulls_for_each_rcu(rc, node, laddr_hb) {
0325         if (llc_dgram_match(sap, laddr, rc)) {
0326             /* Extra checks required by SLAB_TYPESAFE_BY_RCU */
0327             if (unlikely(!refcount_inc_not_zero(&rc->sk_refcnt)))
0328                 goto again;
0329             if (unlikely(llc_sk(rc)->sap != sap ||
0330                      !llc_dgram_match(sap, laddr, rc))) {
0331                 sock_put(rc);
0332                 continue;
0333             }
0334             goto found;
0335         }
0336     }
0337     rc = NULL;
0338     /*
0339      * if the nulls value we got at the end of this lookup is
0340      * not the expected one, we must restart lookup.
0341      * We probably met an item that was moved to another chain.
0342      */
0343     if (unlikely(get_nulls_value(node) != slot))
0344         goto again;
0345 found:
0346     rcu_read_unlock_bh();
0347     return rc;
0348 }
0349 
0350 static inline bool llc_mcast_match(const struct llc_sap *sap,
0351                    const struct llc_addr *laddr,
0352                    const struct sk_buff *skb,
0353                    const struct sock *sk)
0354 {
0355      struct llc_sock *llc = llc_sk(sk);
0356 
0357      return sk->sk_type == SOCK_DGRAM &&
0358       llc->laddr.lsap == laddr->lsap &&
0359       llc->dev == skb->dev;
0360 }
0361 
0362 static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb,
0363              struct sock **stack, int count)
0364 {
0365     struct sk_buff *skb1;
0366     int i;
0367 
0368     for (i = 0; i < count; i++) {
0369         skb1 = skb_clone(skb, GFP_ATOMIC);
0370         if (!skb1) {
0371             sock_put(stack[i]);
0372             continue;
0373         }
0374 
0375         llc_sap_rcv(sap, skb1, stack[i]);
0376         sock_put(stack[i]);
0377     }
0378 }
0379 
0380 /**
0381  *  llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
0382  *  @sap: SAP
0383  *  @laddr: address of local LLC (MAC + SAP)
0384  *  @skb: PDU to deliver
0385  *
0386  *  Search socket list of the SAP and finds connections with same sap.
0387  *  Deliver clone to each.
0388  */
0389 static void llc_sap_mcast(struct llc_sap *sap,
0390               const struct llc_addr *laddr,
0391               struct sk_buff *skb)
0392 {
0393     int i = 0;
0394     struct sock *sk;
0395     struct sock *stack[256 / sizeof(struct sock *)];
0396     struct llc_sock *llc;
0397     struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex);
0398 
0399     spin_lock_bh(&sap->sk_lock);
0400     hlist_for_each_entry(llc, dev_hb, dev_hash_node) {
0401 
0402         sk = &llc->sk;
0403 
0404         if (!llc_mcast_match(sap, laddr, skb, sk))
0405             continue;
0406 
0407         sock_hold(sk);
0408         if (i < ARRAY_SIZE(stack))
0409             stack[i++] = sk;
0410         else {
0411             llc_do_mcast(sap, skb, stack, i);
0412             i = 0;
0413         }
0414     }
0415     spin_unlock_bh(&sap->sk_lock);
0416 
0417     llc_do_mcast(sap, skb, stack, i);
0418 }
0419 
0420 
0421 void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb)
0422 {
0423     struct llc_addr laddr;
0424 
0425     llc_pdu_decode_da(skb, laddr.mac);
0426     llc_pdu_decode_dsap(skb, &laddr.lsap);
0427 
0428     if (is_multicast_ether_addr(laddr.mac)) {
0429         llc_sap_mcast(sap, &laddr, skb);
0430         kfree_skb(skb);
0431     } else {
0432         struct sock *sk = llc_lookup_dgram(sap, &laddr);
0433         if (sk) {
0434             llc_sap_rcv(sap, skb, sk);
0435             sock_put(sk);
0436         } else
0437             kfree_skb(skb);
0438     }
0439 }