1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * LAPB release 002 |
4 | * |
5 | * This code REQUIRES 2.1.15 or higher/ NET3.038 |
6 | * |
7 | * History |
8 | * LAPB 001 Jonathan Naylor Started Coding |
9 | * LAPB 002 Jonathan Naylor New timer architecture. |
10 | */ |
11 | |
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
13 | |
14 | #include <linux/errno.h> |
15 | #include <linux/types.h> |
16 | #include <linux/socket.h> |
17 | #include <linux/in.h> |
18 | #include <linux/kernel.h> |
19 | #include <linux/timer.h> |
20 | #include <linux/string.h> |
21 | #include <linux/sockios.h> |
22 | #include <linux/net.h> |
23 | #include <linux/inet.h> |
24 | #include <linux/skbuff.h> |
25 | #include <linux/slab.h> |
26 | #include <net/sock.h> |
27 | #include <linux/uaccess.h> |
28 | #include <linux/fcntl.h> |
29 | #include <linux/mm.h> |
30 | #include <linux/interrupt.h> |
31 | #include <net/lapb.h> |
32 | |
33 | /* |
34 | * This procedure is passed a buffer descriptor for an iframe. It builds |
35 | * the rest of the control part of the frame and then writes it out. |
36 | */ |
37 | static void lapb_send_iframe(struct lapb_cb *lapb, struct sk_buff *skb, int poll_bit) |
38 | { |
39 | unsigned char *frame; |
40 | |
41 | if (!skb) |
42 | return; |
43 | |
44 | if (lapb->mode & LAPB_EXTENDED) { |
45 | frame = skb_push(skb, len: 2); |
46 | |
47 | frame[0] = LAPB_I; |
48 | frame[0] |= lapb->vs << 1; |
49 | frame[1] = poll_bit ? LAPB_EPF : 0; |
50 | frame[1] |= lapb->vr << 1; |
51 | } else { |
52 | frame = skb_push(skb, len: 1); |
53 | |
54 | *frame = LAPB_I; |
55 | *frame |= poll_bit ? LAPB_SPF : 0; |
56 | *frame |= lapb->vr << 5; |
57 | *frame |= lapb->vs << 1; |
58 | } |
59 | |
60 | lapb_dbg(1, "(%p) S%d TX I(%d) S%d R%d\n" , |
61 | lapb->dev, lapb->state, poll_bit, lapb->vs, lapb->vr); |
62 | |
63 | lapb_transmit_buffer(lapb, skb, LAPB_COMMAND); |
64 | } |
65 | |
66 | void lapb_kick(struct lapb_cb *lapb) |
67 | { |
68 | struct sk_buff *skb, *skbn; |
69 | unsigned short modulus, start, end; |
70 | |
71 | modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; |
72 | start = !skb_peek(list_: &lapb->ack_queue) ? lapb->va : lapb->vs; |
73 | end = (lapb->va + lapb->window) % modulus; |
74 | |
75 | if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) && |
76 | start != end && skb_peek(list_: &lapb->write_queue)) { |
77 | lapb->vs = start; |
78 | |
79 | /* |
80 | * Dequeue the frame and copy it. |
81 | */ |
82 | skb = skb_dequeue(list: &lapb->write_queue); |
83 | |
84 | do { |
85 | skbn = skb_copy(skb, GFP_ATOMIC); |
86 | if (!skbn) { |
87 | skb_queue_head(list: &lapb->write_queue, newsk: skb); |
88 | break; |
89 | } |
90 | |
91 | if (skb->sk) |
92 | skb_set_owner_w(skb: skbn, sk: skb->sk); |
93 | |
94 | /* |
95 | * Transmit the frame copy. |
96 | */ |
97 | lapb_send_iframe(lapb, skb: skbn, LAPB_POLLOFF); |
98 | |
99 | lapb->vs = (lapb->vs + 1) % modulus; |
100 | |
101 | /* |
102 | * Requeue the original data frame. |
103 | */ |
104 | skb_queue_tail(list: &lapb->ack_queue, newsk: skb); |
105 | |
106 | } while (lapb->vs != end && (skb = skb_dequeue(list: &lapb->write_queue)) != NULL); |
107 | |
108 | lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; |
109 | |
110 | if (!lapb_t1timer_running(lapb)) |
111 | lapb_start_t1timer(lapb); |
112 | } |
113 | } |
114 | |
115 | void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *skb, int type) |
116 | { |
117 | unsigned char *ptr; |
118 | |
119 | ptr = skb_push(skb, len: 1); |
120 | |
121 | if (lapb->mode & LAPB_MLP) { |
122 | if (lapb->mode & LAPB_DCE) { |
123 | if (type == LAPB_COMMAND) |
124 | *ptr = LAPB_ADDR_C; |
125 | if (type == LAPB_RESPONSE) |
126 | *ptr = LAPB_ADDR_D; |
127 | } else { |
128 | if (type == LAPB_COMMAND) |
129 | *ptr = LAPB_ADDR_D; |
130 | if (type == LAPB_RESPONSE) |
131 | *ptr = LAPB_ADDR_C; |
132 | } |
133 | } else { |
134 | if (lapb->mode & LAPB_DCE) { |
135 | if (type == LAPB_COMMAND) |
136 | *ptr = LAPB_ADDR_A; |
137 | if (type == LAPB_RESPONSE) |
138 | *ptr = LAPB_ADDR_B; |
139 | } else { |
140 | if (type == LAPB_COMMAND) |
141 | *ptr = LAPB_ADDR_B; |
142 | if (type == LAPB_RESPONSE) |
143 | *ptr = LAPB_ADDR_A; |
144 | } |
145 | } |
146 | |
147 | lapb_dbg(2, "(%p) S%d TX %3ph\n" , lapb->dev, lapb->state, skb->data); |
148 | |
149 | if (!lapb_data_transmit(lapb, skb)) |
150 | kfree_skb(skb); |
151 | } |
152 | |
153 | void lapb_establish_data_link(struct lapb_cb *lapb) |
154 | { |
155 | lapb->condition = 0x00; |
156 | lapb->n2count = 0; |
157 | |
158 | if (lapb->mode & LAPB_EXTENDED) { |
159 | lapb_dbg(1, "(%p) S%d TX SABME(1)\n" , lapb->dev, lapb->state); |
160 | lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); |
161 | } else { |
162 | lapb_dbg(1, "(%p) S%d TX SABM(1)\n" , lapb->dev, lapb->state); |
163 | lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); |
164 | } |
165 | |
166 | lapb_start_t1timer(lapb); |
167 | lapb_stop_t2timer(lapb); |
168 | } |
169 | |
170 | void lapb_enquiry_response(struct lapb_cb *lapb) |
171 | { |
172 | lapb_dbg(1, "(%p) S%d TX RR(1) R%d\n" , |
173 | lapb->dev, lapb->state, lapb->vr); |
174 | |
175 | lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE); |
176 | |
177 | lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; |
178 | } |
179 | |
180 | void lapb_timeout_response(struct lapb_cb *lapb) |
181 | { |
182 | lapb_dbg(1, "(%p) S%d TX RR(0) R%d\n" , |
183 | lapb->dev, lapb->state, lapb->vr); |
184 | lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE); |
185 | |
186 | lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; |
187 | } |
188 | |
189 | void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short nr) |
190 | { |
191 | if (lapb->vs == nr) { |
192 | lapb_frames_acked(lapb, nr); |
193 | lapb_stop_t1timer(lapb); |
194 | lapb->n2count = 0; |
195 | } else if (lapb->va != nr) { |
196 | lapb_frames_acked(lapb, nr); |
197 | lapb_start_t1timer(lapb); |
198 | } |
199 | } |
200 | |
201 | void lapb_check_need_response(struct lapb_cb *lapb, int type, int pf) |
202 | { |
203 | if (type == LAPB_COMMAND && pf) |
204 | lapb_enquiry_response(lapb); |
205 | } |
206 | |