forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/drivers/net/wan/hdlc_x25.c
....@@ -1,12 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Generic HDLC support routines for Linux
34 * X.25 support
45 *
56 * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
6
- *
7
- * This program is free software; you can redistribute it and/or modify it
8
- * under the terms of version 2 of the GNU General Public License
9
- * as published by the Free Software Foundation.
107 */
118
129 #include <linux/errno.h>
....@@ -24,7 +21,18 @@
2421 #include <linux/skbuff.h>
2522 #include <net/x25device.h>
2623
24
+struct x25_state {
25
+ x25_hdlc_proto settings;
26
+ bool up;
27
+ spinlock_t up_lock; /* Protects "up" */
28
+};
29
+
2730 static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
31
+
32
+static struct x25_state *state(hdlc_device *hdlc)
33
+{
34
+ return hdlc->state;
35
+}
2836
2937 /* These functions are callbacks called by LAPB layer */
3038
....@@ -65,10 +73,13 @@
6573 {
6674 unsigned char *ptr;
6775
68
- skb_push(skb, 1);
69
-
70
- if (skb_cow(skb, 1))
76
+ if (skb_cow(skb, 1)) {
77
+ kfree_skb(skb);
7178 return NET_RX_DROP;
79
+ }
80
+
81
+ skb_push(skb, 1);
82
+ skb_reset_network_header(skb);
7283
7384 ptr = skb->data;
7485 *ptr = X25_IFACE_DATA;
....@@ -82,6 +93,13 @@
8293 static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)
8394 {
8495 hdlc_device *hdlc = dev_to_hdlc(dev);
96
+
97
+ skb_reset_network_header(skb);
98
+ skb->protocol = hdlc_type_trans(skb, dev);
99
+
100
+ if (dev_nit_active(dev))
101
+ dev_queue_xmit_nit(skb, dev);
102
+
85103 hdlc->xmit(skb, dev); /* Ignore return value :-( */
86104 }
87105
....@@ -89,15 +107,32 @@
89107
90108 static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
91109 {
110
+ hdlc_device *hdlc = dev_to_hdlc(dev);
111
+ struct x25_state *x25st = state(hdlc);
92112 int result;
93113
114
+ /* There should be a pseudo header of 1 byte added by upper layers.
115
+ * Check to make sure it is there before reading it.
116
+ */
117
+ if (skb->len < 1) {
118
+ kfree_skb(skb);
119
+ return NETDEV_TX_OK;
120
+ }
94121
95
- /* X.25 to LAPB */
122
+ spin_lock_bh(&x25st->up_lock);
123
+ if (!x25st->up) {
124
+ spin_unlock_bh(&x25st->up_lock);
125
+ kfree_skb(skb);
126
+ return NETDEV_TX_OK;
127
+ }
128
+
96129 switch (skb->data[0]) {
97130 case X25_IFACE_DATA: /* Data to be transmitted */
98131 skb_pull(skb, 1);
132
+ skb_reset_network_header(skb);
99133 if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
100134 dev_kfree_skb(skb);
135
+ spin_unlock_bh(&x25st->up_lock);
101136 return NETDEV_TX_OK;
102137
103138 case X25_IFACE_CONNECT:
....@@ -126,6 +161,7 @@
126161 break;
127162 }
128163
164
+ spin_unlock_bh(&x25st->up_lock);
129165 dev_kfree_skb(skb);
130166 return NETDEV_TX_OK;
131167 }
....@@ -134,7 +170,6 @@
134170
135171 static int x25_open(struct net_device *dev)
136172 {
137
- int result;
138173 static const struct lapb_register_struct cb = {
139174 .connect_confirmation = x25_connected,
140175 .connect_indication = x25_connected,
....@@ -143,10 +178,38 @@
143178 .data_indication = x25_data_indication,
144179 .data_transmit = x25_data_transmit,
145180 };
181
+ hdlc_device *hdlc = dev_to_hdlc(dev);
182
+ struct x25_state *x25st = state(hdlc);
183
+ struct lapb_parms_struct params;
184
+ int result;
146185
147186 result = lapb_register(dev, &cb);
148187 if (result != LAPB_OK)
149
- return result;
188
+ return -ENOMEM;
189
+
190
+ result = lapb_getparms(dev, &params);
191
+ if (result != LAPB_OK)
192
+ return -EINVAL;
193
+
194
+ if (state(hdlc)->settings.dce)
195
+ params.mode = params.mode | LAPB_DCE;
196
+
197
+ if (state(hdlc)->settings.modulo == 128)
198
+ params.mode = params.mode | LAPB_EXTENDED;
199
+
200
+ params.window = state(hdlc)->settings.window;
201
+ params.t1 = state(hdlc)->settings.t1;
202
+ params.t2 = state(hdlc)->settings.t2;
203
+ params.n2 = state(hdlc)->settings.n2;
204
+
205
+ result = lapb_setparms(dev, &params);
206
+ if (result != LAPB_OK)
207
+ return -EINVAL;
208
+
209
+ spin_lock_bh(&x25st->up_lock);
210
+ x25st->up = true;
211
+ spin_unlock_bh(&x25st->up_lock);
212
+
150213 return 0;
151214 }
152215
....@@ -154,6 +217,13 @@
154217
155218 static void x25_close(struct net_device *dev)
156219 {
220
+ hdlc_device *hdlc = dev_to_hdlc(dev);
221
+ struct x25_state *x25st = state(hdlc);
222
+
223
+ spin_lock_bh(&x25st->up_lock);
224
+ x25st->up = false;
225
+ spin_unlock_bh(&x25st->up_lock);
226
+
157227 lapb_unregister(dev);
158228 }
159229
....@@ -162,15 +232,28 @@
162232 static int x25_rx(struct sk_buff *skb)
163233 {
164234 struct net_device *dev = skb->dev;
235
+ hdlc_device *hdlc = dev_to_hdlc(dev);
236
+ struct x25_state *x25st = state(hdlc);
165237
166238 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
167239 dev->stats.rx_dropped++;
168240 return NET_RX_DROP;
169241 }
170242
171
- if (lapb_data_received(dev, skb) == LAPB_OK)
172
- return NET_RX_SUCCESS;
243
+ spin_lock_bh(&x25st->up_lock);
244
+ if (!x25st->up) {
245
+ spin_unlock_bh(&x25st->up_lock);
246
+ kfree_skb(skb);
247
+ dev->stats.rx_dropped++;
248
+ return NET_RX_DROP;
249
+ }
173250
251
+ if (lapb_data_received(dev, skb) == LAPB_OK) {
252
+ spin_unlock_bh(&x25st->up_lock);
253
+ return NET_RX_SUCCESS;
254
+ }
255
+
256
+ spin_unlock_bh(&x25st->up_lock);
174257 dev->stats.rx_errors++;
175258 dev_kfree_skb_any(skb);
176259 return NET_RX_DROP;
....@@ -189,7 +272,10 @@
189272
190273 static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
191274 {
275
+ x25_hdlc_proto __user *x25_s = ifr->ifr_settings.ifs_ifsu.x25;
276
+ const size_t size = sizeof(x25_hdlc_proto);
192277 hdlc_device *hdlc = dev_to_hdlc(dev);
278
+ x25_hdlc_proto new_settings;
193279 int result;
194280
195281 switch (ifr->ifr_settings.type) {
....@@ -197,7 +283,13 @@
197283 if (dev_to_hdlc(dev)->proto != &proto)
198284 return -EINVAL;
199285 ifr->ifr_settings.type = IF_PROTO_X25;
200
- return 0; /* return protocol only, no settable parameters */
286
+ if (ifr->ifr_settings.size < size) {
287
+ ifr->ifr_settings.size = size; /* data size wanted */
288
+ return -ENOBUFS;
289
+ }
290
+ if (copy_to_user(x25_s, &state(hdlc)->settings, size))
291
+ return -EFAULT;
292
+ return 0;
201293
202294 case IF_PROTO_X25:
203295 if (!capable(CAP_NET_ADMIN))
....@@ -206,12 +298,57 @@
206298 if (dev->flags & IFF_UP)
207299 return -EBUSY;
208300
301
+ /* backward compatibility */
302
+ if (ifr->ifr_settings.size == 0) {
303
+ new_settings.dce = 0;
304
+ new_settings.modulo = 8;
305
+ new_settings.window = 7;
306
+ new_settings.t1 = 3;
307
+ new_settings.t2 = 1;
308
+ new_settings.n2 = 10;
309
+ }
310
+ else {
311
+ if (copy_from_user(&new_settings, x25_s, size))
312
+ return -EFAULT;
313
+
314
+ if ((new_settings.dce != 0 &&
315
+ new_settings.dce != 1) ||
316
+ (new_settings.modulo != 8 &&
317
+ new_settings.modulo != 128) ||
318
+ new_settings.window < 1 ||
319
+ (new_settings.modulo == 8 &&
320
+ new_settings.window > 7) ||
321
+ (new_settings.modulo == 128 &&
322
+ new_settings.window > 127) ||
323
+ new_settings.t1 < 1 ||
324
+ new_settings.t1 > 255 ||
325
+ new_settings.t2 < 1 ||
326
+ new_settings.t2 > 255 ||
327
+ new_settings.n2 < 1 ||
328
+ new_settings.n2 > 255)
329
+ return -EINVAL;
330
+ }
331
+
209332 result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
210333 if (result)
211334 return result;
212335
213
- if ((result = attach_hdlc_protocol(dev, &proto, 0)))
336
+ if ((result = attach_hdlc_protocol(dev, &proto,
337
+ sizeof(struct x25_state))))
214338 return result;
339
+
340
+ memcpy(&state(hdlc)->settings, &new_settings, size);
341
+ state(hdlc)->up = false;
342
+ spin_lock_init(&state(hdlc)->up_lock);
343
+
344
+ /* There's no header_ops so hard_header_len should be 0. */
345
+ dev->hard_header_len = 0;
346
+ /* When transmitting data:
347
+ * first we'll remove a pseudo header of 1 byte,
348
+ * then we'll prepend an LAPB header of at most 3 bytes.
349
+ */
350
+ dev->needed_headroom = 3 - 1;
351
+
215352 dev->type = ARPHRD_X25;
216353 call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);
217354 netif_dormant_off(dev);