^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * llc_if.c - Defines LLC interface to upper layer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 1997 by Procom Technology, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This program can be redistributed or modified under the terms of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * GNU General Public License as published by the Free Software Foundation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * This program is distributed without any warranty or implied warranty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * of merchantability or fitness for a particular purpose.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * See the GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/gfp.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 <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <net/llc_if.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <net/llc_sap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <net/llc_s_ev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <net/llc_conn.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <net/sock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <net/llc_c_ev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <net/llc_c_ac.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <net/llc_c_st.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <net/tcp_states.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * llc_build_and_send_pkt - Connection data sending for upper layers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * @sk: connection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * @skb: packet to send
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * This function is called when upper layer wants to send data using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * connection oriented communication mode. During sending data, connection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * will be locked and received frames and expired timers will be queued.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Returns 0 for success, -ECONNABORTED when the connection already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * closed and -EBUSY when sending data is not permitted in this state or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * LLC has send an I pdu with p bit set to 1 and is waiting for it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * response.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * This function always consumes a reference to the skb.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct llc_conn_state_ev *ev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int rc = -ECONNABORTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct llc_sock *llc = llc_sk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (unlikely(llc->state == LLC_CONN_STATE_ADM))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) rc = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (unlikely(llc_data_accept_state(llc->state) || /* data_conn_refuse */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) llc->p_flag)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) llc->failed_data_req = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ev = llc_conn_ev(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ev->type = LLC_CONN_EV_TYPE_PRIM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ev->prim = LLC_DATA_PRIM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ev->prim_type = LLC_PRIM_TYPE_REQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) skb->dev = llc->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return llc_conn_state_process(sk, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * llc_establish_connection - Called by upper layer to establish a conn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * @sk: connection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * @lmac: local mac address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * @dmac: destination mac address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * @dsap: destination sap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * Upper layer calls this to establish an LLC connection with a remote
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * machine. This function packages a proper event and sends it connection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * component state machine. Success or failure of connection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * establishment will inform to upper layer via calling it's confirm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * function and passing proper information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int rc = -EISCONN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct llc_addr laddr, daddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct llc_sock *llc = llc_sk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct sock *existing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) laddr.lsap = llc->sap->laddr.lsap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) daddr.lsap = dsap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) memcpy(daddr.mac, dmac, sizeof(daddr.mac));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) memcpy(laddr.mac, lmac, sizeof(laddr.mac));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) existing = llc_lookup_established(llc->sap, &daddr, &laddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (existing) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (existing->sk_state == TCP_ESTABLISHED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) sk = existing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) goto out_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) sock_put(existing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) sock_hold(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) skb = alloc_skb(0, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct llc_conn_state_ev *ev = llc_conn_ev(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) ev->type = LLC_CONN_EV_TYPE_PRIM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ev->prim = LLC_CONN_PRIM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) ev->prim_type = LLC_PRIM_TYPE_REQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) skb_set_owner_w(skb, sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) rc = llc_conn_state_process(sk, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) out_put:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) sock_put(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * llc_send_disc - Called by upper layer to close a connection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * @sk: connection to be closed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * Upper layer calls this when it wants to close an established LLC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * connection with a remote machine. This function packages a proper event
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * and sends it to connection component state machine. Returns 0 for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * success, 1 otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int llc_send_disc(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) u16 rc = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct llc_conn_state_ev *ev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) sock_hold(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (sk->sk_type != SOCK_STREAM || sk->sk_state != TCP_ESTABLISHED ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * Postpone unassigning the connection from its SAP and returning the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * connection until all ACTIONs have been completely executed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) skb = alloc_skb(0, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (!skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) skb_set_owner_w(skb, sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) sk->sk_state = TCP_CLOSING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) ev = llc_conn_ev(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ev->type = LLC_CONN_EV_TYPE_PRIM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ev->prim = LLC_DISC_PRIM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) ev->prim_type = LLC_PRIM_TYPE_REQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) rc = llc_conn_state_process(sk, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) sock_put(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }