Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/lapb/lapb_out.c
26146 views
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, 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, 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(&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(&lapb->write_queue)) {
77
lapb->vs = start;
78
79
/*
80
* Dequeue the frame and copy it.
81
*/
82
skb = skb_dequeue(&lapb->write_queue);
83
84
do {
85
skbn = skb_copy(skb, GFP_ATOMIC);
86
if (!skbn) {
87
skb_queue_head(&lapb->write_queue, skb);
88
break;
89
}
90
91
if (skb->sk)
92
skb_set_owner_w(skbn, skb->sk);
93
94
/*
95
* Transmit the frame copy.
96
*/
97
lapb_send_iframe(lapb, skbn, LAPB_POLLOFF);
98
99
lapb->vs = (lapb->vs + 1) % modulus;
100
101
/*
102
* Requeue the original data frame.
103
*/
104
skb_queue_tail(&lapb->ack_queue, skb);
105
106
} while (lapb->vs != end && (skb = skb_dequeue(&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, 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
207