1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/gfp.h>
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/netdevice.h>
18#include <linux/errno.h>
19#include <net/llc_if.h>
20#include <net/llc_sap.h>
21#include <net/llc_s_ev.h>
22#include <net/llc_conn.h>
23#include <net/sock.h>
24#include <net/llc_c_ev.h>
25#include <net/llc_c_ac.h>
26#include <net/llc_c_st.h>
27#include <net/tcp_states.h>
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
45{
46 struct llc_conn_state_ev *ev;
47 int rc = -ECONNABORTED;
48 struct llc_sock *llc = llc_sk(sk);
49
50 if (unlikely(llc->state == LLC_CONN_STATE_ADM))
51 goto out_free;
52 rc = -EBUSY;
53 if (unlikely(llc_data_accept_state(llc->state) ||
54 llc->p_flag)) {
55 llc->failed_data_req = 1;
56 goto out_free;
57 }
58 ev = llc_conn_ev(skb);
59 ev->type = LLC_CONN_EV_TYPE_PRIM;
60 ev->prim = LLC_DATA_PRIM;
61 ev->prim_type = LLC_PRIM_TYPE_REQ;
62 skb->dev = llc->dev;
63 return llc_conn_state_process(sk, skb);
64
65out_free:
66 kfree_skb(skb);
67 return rc;
68}
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap)
84{
85 int rc = -EISCONN;
86 struct llc_addr laddr, daddr;
87 struct sk_buff *skb;
88 struct llc_sock *llc = llc_sk(sk);
89 struct sock *existing;
90
91 laddr.lsap = llc->sap->laddr.lsap;
92 daddr.lsap = dsap;
93 memcpy(daddr.mac, dmac, sizeof(daddr.mac));
94 memcpy(laddr.mac, lmac, sizeof(laddr.mac));
95 existing = llc_lookup_established(llc->sap, &daddr, &laddr);
96 if (existing) {
97 if (existing->sk_state == TCP_ESTABLISHED) {
98 sk = existing;
99 goto out_put;
100 } else
101 sock_put(existing);
102 }
103 sock_hold(sk);
104 rc = -ENOMEM;
105 skb = alloc_skb(0, GFP_ATOMIC);
106 if (skb) {
107 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
108
109 ev->type = LLC_CONN_EV_TYPE_PRIM;
110 ev->prim = LLC_CONN_PRIM;
111 ev->prim_type = LLC_PRIM_TYPE_REQ;
112 skb_set_owner_w(skb, sk);
113 rc = llc_conn_state_process(sk, skb);
114 }
115out_put:
116 sock_put(sk);
117 return rc;
118}
119
120
121
122
123
124
125
126
127
128
129int llc_send_disc(struct sock *sk)
130{
131 u16 rc = 1;
132 struct llc_conn_state_ev *ev;
133 struct sk_buff *skb;
134
135 sock_hold(sk);
136 if (sk->sk_type != SOCK_STREAM || sk->sk_state != TCP_ESTABLISHED ||
137 llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
138 llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC)
139 goto out;
140
141
142
143
144 skb = alloc_skb(0, GFP_ATOMIC);
145 if (!skb)
146 goto out;
147 skb_set_owner_w(skb, sk);
148 sk->sk_state = TCP_CLOSING;
149 ev = llc_conn_ev(skb);
150 ev->type = LLC_CONN_EV_TYPE_PRIM;
151 ev->prim = LLC_DISC_PRIM;
152 ev->prim_type = LLC_PRIM_TYPE_REQ;
153 rc = llc_conn_state_process(sk, skb);
154out:
155 sock_put(sk);
156 return rc;
157}
158