Thomas Gleixner | ee5d8f4 | 2019-05-20 19:08:06 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | /* |
| 3 | * LAPB release 002 |
| 4 | * |
| 5 | * This code REQUIRES 2.1.15 or higher/ NET3.038 |
| 6 | * |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 | * History |
| 8 | * LAPB 001 Jonathan Naylor Started Coding |
| 9 | * LAPB 002 Jonathan Naylor New timer architecture. |
| 10 | * 2000-10-29 Henner Eisen lapb_data_indication() return status. |
| 11 | */ |
YOSHIFUJI Hideaki | 56d6c3d | 2007-02-09 23:24:59 +0900 | [diff] [blame] | 12 | |
Joe Perches | a508da6 | 2012-05-17 10:25:49 +0000 | [diff] [blame] | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 14 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/module.h> |
| 16 | #include <linux/errno.h> |
| 17 | #include <linux/types.h> |
| 18 | #include <linux/socket.h> |
| 19 | #include <linux/in.h> |
| 20 | #include <linux/kernel.h> |
| 21 | #include <linux/jiffies.h> |
| 22 | #include <linux/timer.h> |
| 23 | #include <linux/string.h> |
| 24 | #include <linux/sockios.h> |
| 25 | #include <linux/net.h> |
| 26 | #include <linux/inet.h> |
| 27 | #include <linux/if_arp.h> |
| 28 | #include <linux/skbuff.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 29 | #include <linux/slab.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 | #include <net/sock.h> |
Linus Torvalds | 7c0f6ba | 2016-12-24 11:46:01 -0800 | [diff] [blame] | 31 | #include <linux/uaccess.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 32 | #include <linux/fcntl.h> |
| 33 | #include <linux/mm.h> |
| 34 | #include <linux/interrupt.h> |
| 35 | #include <linux/stat.h> |
| 36 | #include <linux/init.h> |
| 37 | #include <net/lapb.h> |
| 38 | |
Denis Cheng | 14d0e7b | 2007-12-07 00:50:15 -0800 | [diff] [blame] | 39 | static LIST_HEAD(lapb_list); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | static DEFINE_RWLOCK(lapb_list_lock); |
| 41 | |
| 42 | /* |
YOSHIFUJI Hideaki | 56d6c3d | 2007-02-09 23:24:59 +0900 | [diff] [blame] | 43 | * Free an allocated lapb control block. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | */ |
| 45 | static void lapb_free_cb(struct lapb_cb *lapb) |
| 46 | { |
| 47 | kfree(lapb); |
| 48 | } |
| 49 | |
| 50 | static __inline__ void lapb_hold(struct lapb_cb *lapb) |
| 51 | { |
Reshetova, Elena | 0408c58 | 2017-07-04 15:53:08 +0300 | [diff] [blame] | 52 | refcount_inc(&lapb->refcnt); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | static __inline__ void lapb_put(struct lapb_cb *lapb) |
| 56 | { |
Reshetova, Elena | 0408c58 | 2017-07-04 15:53:08 +0300 | [diff] [blame] | 57 | if (refcount_dec_and_test(&lapb->refcnt)) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 58 | lapb_free_cb(lapb); |
| 59 | } |
| 60 | |
| 61 | /* |
| 62 | * Socket removal during an interrupt is now safe. |
| 63 | */ |
| 64 | static void __lapb_remove_cb(struct lapb_cb *lapb) |
| 65 | { |
| 66 | if (lapb->node.next) { |
| 67 | list_del(&lapb->node); |
| 68 | lapb_put(lapb); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | /* |
| 73 | * Add a socket to the bound sockets list. |
| 74 | */ |
| 75 | static void __lapb_insert_cb(struct lapb_cb *lapb) |
| 76 | { |
| 77 | list_add(&lapb->node, &lapb_list); |
| 78 | lapb_hold(lapb); |
| 79 | } |
| 80 | |
| 81 | static struct lapb_cb *__lapb_devtostruct(struct net_device *dev) |
| 82 | { |
| 83 | struct list_head *entry; |
| 84 | struct lapb_cb *lapb, *use = NULL; |
| 85 | |
| 86 | list_for_each(entry, &lapb_list) { |
| 87 | lapb = list_entry(entry, struct lapb_cb, node); |
| 88 | if (lapb->dev == dev) { |
| 89 | use = lapb; |
| 90 | break; |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | if (use) |
| 95 | lapb_hold(use); |
| 96 | |
| 97 | return use; |
| 98 | } |
| 99 | |
| 100 | static struct lapb_cb *lapb_devtostruct(struct net_device *dev) |
| 101 | { |
| 102 | struct lapb_cb *rc; |
| 103 | |
| 104 | read_lock_bh(&lapb_list_lock); |
| 105 | rc = __lapb_devtostruct(dev); |
| 106 | read_unlock_bh(&lapb_list_lock); |
| 107 | |
| 108 | return rc; |
| 109 | } |
| 110 | /* |
| 111 | * Create an empty LAPB control block. |
| 112 | */ |
| 113 | static struct lapb_cb *lapb_create_cb(void) |
| 114 | { |
Panagiotis Issaris | 0da974f | 2006-07-21 14:51:30 -0700 | [diff] [blame] | 115 | struct lapb_cb *lapb = kzalloc(sizeof(*lapb), GFP_ATOMIC); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 117 | if (!lapb) |
| 118 | goto out; |
| 119 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | skb_queue_head_init(&lapb->write_queue); |
| 121 | skb_queue_head_init(&lapb->ack_queue); |
| 122 | |
Kees Cook | 83a37b3 | 2017-10-16 17:28:46 -0700 | [diff] [blame] | 123 | timer_setup(&lapb->t1timer, NULL, 0); |
| 124 | timer_setup(&lapb->t2timer, NULL, 0); |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 125 | lapb->t1timer_stop = true; |
| 126 | lapb->t2timer_stop = true; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | |
| 128 | lapb->t1 = LAPB_DEFAULT_T1; |
| 129 | lapb->t2 = LAPB_DEFAULT_T2; |
| 130 | lapb->n2 = LAPB_DEFAULT_N2; |
| 131 | lapb->mode = LAPB_DEFAULT_MODE; |
| 132 | lapb->window = LAPB_DEFAULT_WINDOW; |
| 133 | lapb->state = LAPB_STATE_0; |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 134 | |
| 135 | spin_lock_init(&lapb->lock); |
Reshetova, Elena | 0408c58 | 2017-07-04 15:53:08 +0300 | [diff] [blame] | 136 | refcount_set(&lapb->refcnt, 1); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 137 | out: |
| 138 | return lapb; |
| 139 | } |
| 140 | |
stephen hemminger | d97a077 | 2011-09-16 11:04:29 +0000 | [diff] [blame] | 141 | int lapb_register(struct net_device *dev, |
| 142 | const struct lapb_register_struct *callbacks) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | { |
| 144 | struct lapb_cb *lapb; |
| 145 | int rc = LAPB_BADTOKEN; |
| 146 | |
| 147 | write_lock_bh(&lapb_list_lock); |
| 148 | |
| 149 | lapb = __lapb_devtostruct(dev); |
| 150 | if (lapb) { |
| 151 | lapb_put(lapb); |
| 152 | goto out; |
| 153 | } |
| 154 | |
| 155 | lapb = lapb_create_cb(); |
| 156 | rc = LAPB_NOMEM; |
| 157 | if (!lapb) |
| 158 | goto out; |
| 159 | |
| 160 | lapb->dev = dev; |
stephen hemminger | d97a077 | 2011-09-16 11:04:29 +0000 | [diff] [blame] | 161 | lapb->callbacks = callbacks; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 162 | |
| 163 | __lapb_insert_cb(lapb); |
| 164 | |
| 165 | lapb_start_t1timer(lapb); |
| 166 | |
| 167 | rc = LAPB_OK; |
| 168 | out: |
| 169 | write_unlock_bh(&lapb_list_lock); |
| 170 | return rc; |
| 171 | } |
Jeremy Sowden | 4201c92 | 2019-06-16 11:41:59 +0100 | [diff] [blame] | 172 | EXPORT_SYMBOL(lapb_register); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 173 | |
| 174 | int lapb_unregister(struct net_device *dev) |
| 175 | { |
| 176 | struct lapb_cb *lapb; |
| 177 | int rc = LAPB_BADTOKEN; |
| 178 | |
| 179 | write_lock_bh(&lapb_list_lock); |
| 180 | lapb = __lapb_devtostruct(dev); |
| 181 | if (!lapb) |
| 182 | goto out; |
Jeremy Sowden | 6be8e29 | 2019-06-16 16:54:37 +0100 | [diff] [blame] | 183 | lapb_put(lapb); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 184 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 185 | /* Wait for other refs to "lapb" to drop */ |
| 186 | while (refcount_read(&lapb->refcnt) > 2) |
| 187 | usleep_range(1, 10); |
| 188 | |
| 189 | spin_lock_bh(&lapb->lock); |
| 190 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 191 | lapb_stop_t1timer(lapb); |
| 192 | lapb_stop_t2timer(lapb); |
| 193 | |
| 194 | lapb_clear_queues(lapb); |
| 195 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 196 | spin_unlock_bh(&lapb->lock); |
| 197 | |
| 198 | /* Wait for running timers to stop */ |
| 199 | del_timer_sync(&lapb->t1timer); |
| 200 | del_timer_sync(&lapb->t2timer); |
| 201 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 202 | __lapb_remove_cb(lapb); |
| 203 | |
| 204 | lapb_put(lapb); |
| 205 | rc = LAPB_OK; |
| 206 | out: |
| 207 | write_unlock_bh(&lapb_list_lock); |
| 208 | return rc; |
| 209 | } |
Fabian Frederick | 75da146 | 2014-10-22 21:01:41 +0200 | [diff] [blame] | 210 | EXPORT_SYMBOL(lapb_unregister); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 211 | |
| 212 | int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms) |
| 213 | { |
| 214 | int rc = LAPB_BADTOKEN; |
| 215 | struct lapb_cb *lapb = lapb_devtostruct(dev); |
| 216 | |
| 217 | if (!lapb) |
| 218 | goto out; |
| 219 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 220 | spin_lock_bh(&lapb->lock); |
| 221 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 222 | parms->t1 = lapb->t1 / HZ; |
| 223 | parms->t2 = lapb->t2 / HZ; |
| 224 | parms->n2 = lapb->n2; |
| 225 | parms->n2count = lapb->n2count; |
| 226 | parms->state = lapb->state; |
| 227 | parms->window = lapb->window; |
| 228 | parms->mode = lapb->mode; |
| 229 | |
| 230 | if (!timer_pending(&lapb->t1timer)) |
| 231 | parms->t1timer = 0; |
| 232 | else |
| 233 | parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ; |
| 234 | |
| 235 | if (!timer_pending(&lapb->t2timer)) |
| 236 | parms->t2timer = 0; |
| 237 | else |
| 238 | parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ; |
| 239 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 240 | spin_unlock_bh(&lapb->lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 241 | lapb_put(lapb); |
| 242 | rc = LAPB_OK; |
| 243 | out: |
| 244 | return rc; |
| 245 | } |
Fabian Frederick | 75da146 | 2014-10-22 21:01:41 +0200 | [diff] [blame] | 246 | EXPORT_SYMBOL(lapb_getparms); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 247 | |
| 248 | int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms) |
| 249 | { |
| 250 | int rc = LAPB_BADTOKEN; |
| 251 | struct lapb_cb *lapb = lapb_devtostruct(dev); |
| 252 | |
| 253 | if (!lapb) |
| 254 | goto out; |
| 255 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 256 | spin_lock_bh(&lapb->lock); |
| 257 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 258 | rc = LAPB_INVALUE; |
| 259 | if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1) |
| 260 | goto out_put; |
| 261 | |
| 262 | if (lapb->state == LAPB_STATE_0) { |
Diego Calleja | 558e10a | 2006-08-05 21:15:58 -0700 | [diff] [blame] | 263 | if (parms->mode & LAPB_EXTENDED) { |
| 264 | if (parms->window < 1 || parms->window > 127) |
| 265 | goto out_put; |
| 266 | } else { |
| 267 | if (parms->window < 1 || parms->window > 7) |
| 268 | goto out_put; |
| 269 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 270 | lapb->mode = parms->mode; |
| 271 | lapb->window = parms->window; |
| 272 | } |
| 273 | |
| 274 | lapb->t1 = parms->t1 * HZ; |
| 275 | lapb->t2 = parms->t2 * HZ; |
| 276 | lapb->n2 = parms->n2; |
| 277 | |
| 278 | rc = LAPB_OK; |
| 279 | out_put: |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 280 | spin_unlock_bh(&lapb->lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 281 | lapb_put(lapb); |
| 282 | out: |
| 283 | return rc; |
| 284 | } |
Fabian Frederick | 75da146 | 2014-10-22 21:01:41 +0200 | [diff] [blame] | 285 | EXPORT_SYMBOL(lapb_setparms); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 286 | |
| 287 | int lapb_connect_request(struct net_device *dev) |
| 288 | { |
| 289 | struct lapb_cb *lapb = lapb_devtostruct(dev); |
| 290 | int rc = LAPB_BADTOKEN; |
| 291 | |
| 292 | if (!lapb) |
| 293 | goto out; |
| 294 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 295 | spin_lock_bh(&lapb->lock); |
| 296 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 297 | rc = LAPB_OK; |
| 298 | if (lapb->state == LAPB_STATE_1) |
| 299 | goto out_put; |
| 300 | |
| 301 | rc = LAPB_CONNECTED; |
| 302 | if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4) |
| 303 | goto out_put; |
| 304 | |
| 305 | lapb_establish_data_link(lapb); |
| 306 | |
Joe Perches | a508da6 | 2012-05-17 10:25:49 +0000 | [diff] [blame] | 307 | lapb_dbg(0, "(%p) S0 -> S1\n", lapb->dev); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 308 | lapb->state = LAPB_STATE_1; |
| 309 | |
| 310 | rc = LAPB_OK; |
| 311 | out_put: |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 312 | spin_unlock_bh(&lapb->lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 | lapb_put(lapb); |
| 314 | out: |
| 315 | return rc; |
| 316 | } |
Fabian Frederick | 75da146 | 2014-10-22 21:01:41 +0200 | [diff] [blame] | 317 | EXPORT_SYMBOL(lapb_connect_request); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 318 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 319 | static int __lapb_disconnect_request(struct lapb_cb *lapb) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 320 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 321 | switch (lapb->state) { |
Joe Perches | fcb261f | 2011-07-01 09:43:09 +0000 | [diff] [blame] | 322 | case LAPB_STATE_0: |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 323 | return LAPB_NOTCONNECTED; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 324 | |
Joe Perches | fcb261f | 2011-07-01 09:43:09 +0000 | [diff] [blame] | 325 | case LAPB_STATE_1: |
Joe Perches | a508da6 | 2012-05-17 10:25:49 +0000 | [diff] [blame] | 326 | lapb_dbg(1, "(%p) S1 TX DISC(1)\n", lapb->dev); |
| 327 | lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev); |
Joe Perches | fcb261f | 2011-07-01 09:43:09 +0000 | [diff] [blame] | 328 | lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); |
| 329 | lapb->state = LAPB_STATE_0; |
| 330 | lapb_start_t1timer(lapb); |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 331 | return LAPB_NOTCONNECTED; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 332 | |
Joe Perches | fcb261f | 2011-07-01 09:43:09 +0000 | [diff] [blame] | 333 | case LAPB_STATE_2: |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 334 | return LAPB_OK; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 335 | } |
| 336 | |
| 337 | lapb_clear_queues(lapb); |
| 338 | lapb->n2count = 0; |
| 339 | lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); |
| 340 | lapb_start_t1timer(lapb); |
| 341 | lapb_stop_t2timer(lapb); |
| 342 | lapb->state = LAPB_STATE_2; |
| 343 | |
Joe Perches | a508da6 | 2012-05-17 10:25:49 +0000 | [diff] [blame] | 344 | lapb_dbg(1, "(%p) S3 DISC(1)\n", lapb->dev); |
| 345 | lapb_dbg(0, "(%p) S3 -> S2\n", lapb->dev); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 346 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 347 | return LAPB_OK; |
| 348 | } |
| 349 | |
| 350 | int lapb_disconnect_request(struct net_device *dev) |
| 351 | { |
| 352 | struct lapb_cb *lapb = lapb_devtostruct(dev); |
| 353 | int rc = LAPB_BADTOKEN; |
| 354 | |
| 355 | if (!lapb) |
| 356 | goto out; |
| 357 | |
| 358 | spin_lock_bh(&lapb->lock); |
| 359 | |
| 360 | rc = __lapb_disconnect_request(lapb); |
| 361 | |
| 362 | spin_unlock_bh(&lapb->lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 363 | lapb_put(lapb); |
| 364 | out: |
| 365 | return rc; |
| 366 | } |
Fabian Frederick | 75da146 | 2014-10-22 21:01:41 +0200 | [diff] [blame] | 367 | EXPORT_SYMBOL(lapb_disconnect_request); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 368 | |
| 369 | int lapb_data_request(struct net_device *dev, struct sk_buff *skb) |
| 370 | { |
| 371 | struct lapb_cb *lapb = lapb_devtostruct(dev); |
| 372 | int rc = LAPB_BADTOKEN; |
| 373 | |
| 374 | if (!lapb) |
| 375 | goto out; |
| 376 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 377 | spin_lock_bh(&lapb->lock); |
| 378 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 379 | rc = LAPB_NOTCONNECTED; |
| 380 | if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4) |
| 381 | goto out_put; |
| 382 | |
| 383 | skb_queue_tail(&lapb->write_queue, skb); |
| 384 | lapb_kick(lapb); |
| 385 | rc = LAPB_OK; |
| 386 | out_put: |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 387 | spin_unlock_bh(&lapb->lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 388 | lapb_put(lapb); |
| 389 | out: |
| 390 | return rc; |
| 391 | } |
Fabian Frederick | 75da146 | 2014-10-22 21:01:41 +0200 | [diff] [blame] | 392 | EXPORT_SYMBOL(lapb_data_request); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 393 | |
| 394 | int lapb_data_received(struct net_device *dev, struct sk_buff *skb) |
| 395 | { |
| 396 | struct lapb_cb *lapb = lapb_devtostruct(dev); |
| 397 | int rc = LAPB_BADTOKEN; |
| 398 | |
| 399 | if (lapb) { |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 400 | spin_lock_bh(&lapb->lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 401 | lapb_data_input(lapb, skb); |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 402 | spin_unlock_bh(&lapb->lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 403 | lapb_put(lapb); |
| 404 | rc = LAPB_OK; |
| 405 | } |
| 406 | |
| 407 | return rc; |
| 408 | } |
Fabian Frederick | 75da146 | 2014-10-22 21:01:41 +0200 | [diff] [blame] | 409 | EXPORT_SYMBOL(lapb_data_received); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 410 | |
| 411 | void lapb_connect_confirmation(struct lapb_cb *lapb, int reason) |
| 412 | { |
stephen hemminger | d97a077 | 2011-09-16 11:04:29 +0000 | [diff] [blame] | 413 | if (lapb->callbacks->connect_confirmation) |
| 414 | lapb->callbacks->connect_confirmation(lapb->dev, reason); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 415 | } |
| 416 | |
| 417 | void lapb_connect_indication(struct lapb_cb *lapb, int reason) |
| 418 | { |
stephen hemminger | d97a077 | 2011-09-16 11:04:29 +0000 | [diff] [blame] | 419 | if (lapb->callbacks->connect_indication) |
| 420 | lapb->callbacks->connect_indication(lapb->dev, reason); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 421 | } |
| 422 | |
| 423 | void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason) |
| 424 | { |
stephen hemminger | d97a077 | 2011-09-16 11:04:29 +0000 | [diff] [blame] | 425 | if (lapb->callbacks->disconnect_confirmation) |
| 426 | lapb->callbacks->disconnect_confirmation(lapb->dev, reason); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 427 | } |
| 428 | |
| 429 | void lapb_disconnect_indication(struct lapb_cb *lapb, int reason) |
| 430 | { |
stephen hemminger | d97a077 | 2011-09-16 11:04:29 +0000 | [diff] [blame] | 431 | if (lapb->callbacks->disconnect_indication) |
| 432 | lapb->callbacks->disconnect_indication(lapb->dev, reason); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 433 | } |
| 434 | |
| 435 | int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb) |
| 436 | { |
stephen hemminger | d97a077 | 2011-09-16 11:04:29 +0000 | [diff] [blame] | 437 | if (lapb->callbacks->data_indication) |
| 438 | return lapb->callbacks->data_indication(lapb->dev, skb); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 439 | |
| 440 | kfree_skb(skb); |
Florian Westphal | 0e8635a | 2009-06-20 00:53:25 +0000 | [diff] [blame] | 441 | return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 442 | } |
| 443 | |
| 444 | int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb) |
| 445 | { |
| 446 | int used = 0; |
| 447 | |
stephen hemminger | d97a077 | 2011-09-16 11:04:29 +0000 | [diff] [blame] | 448 | if (lapb->callbacks->data_transmit) { |
| 449 | lapb->callbacks->data_transmit(lapb->dev, skb); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 450 | used = 1; |
| 451 | } |
| 452 | |
| 453 | return used; |
| 454 | } |
| 455 | |
Martin Schiller | a4989fa | 2020-11-26 07:35:54 +0100 | [diff] [blame] | 456 | /* Handle device status changes. */ |
| 457 | static int lapb_device_event(struct notifier_block *this, unsigned long event, |
| 458 | void *ptr) |
| 459 | { |
| 460 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
| 461 | struct lapb_cb *lapb; |
| 462 | |
| 463 | if (!net_eq(dev_net(dev), &init_net)) |
| 464 | return NOTIFY_DONE; |
| 465 | |
| 466 | if (dev->type != ARPHRD_X25) |
| 467 | return NOTIFY_DONE; |
| 468 | |
| 469 | lapb = lapb_devtostruct(dev); |
| 470 | if (!lapb) |
| 471 | return NOTIFY_DONE; |
| 472 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 473 | spin_lock_bh(&lapb->lock); |
| 474 | |
Martin Schiller | a4989fa | 2020-11-26 07:35:54 +0100 | [diff] [blame] | 475 | switch (event) { |
| 476 | case NETDEV_UP: |
| 477 | lapb_dbg(0, "(%p) Interface up: %s\n", dev, dev->name); |
| 478 | |
| 479 | if (netif_carrier_ok(dev)) { |
| 480 | lapb_dbg(0, "(%p): Carrier is already up: %s\n", dev, |
| 481 | dev->name); |
| 482 | if (lapb->mode & LAPB_DCE) { |
| 483 | lapb_start_t1timer(lapb); |
| 484 | } else { |
| 485 | if (lapb->state == LAPB_STATE_0) { |
| 486 | lapb->state = LAPB_STATE_1; |
| 487 | lapb_establish_data_link(lapb); |
| 488 | } |
| 489 | } |
| 490 | } |
| 491 | break; |
| 492 | case NETDEV_GOING_DOWN: |
| 493 | if (netif_carrier_ok(dev)) |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 494 | __lapb_disconnect_request(lapb); |
Martin Schiller | a4989fa | 2020-11-26 07:35:54 +0100 | [diff] [blame] | 495 | break; |
| 496 | case NETDEV_DOWN: |
| 497 | lapb_dbg(0, "(%p) Interface down: %s\n", dev, dev->name); |
| 498 | lapb_dbg(0, "(%p) S%d -> S0\n", dev, lapb->state); |
| 499 | lapb_clear_queues(lapb); |
| 500 | lapb->state = LAPB_STATE_0; |
| 501 | lapb->n2count = 0; |
| 502 | lapb_stop_t1timer(lapb); |
| 503 | lapb_stop_t2timer(lapb); |
| 504 | break; |
| 505 | case NETDEV_CHANGE: |
| 506 | if (netif_carrier_ok(dev)) { |
| 507 | lapb_dbg(0, "(%p): Carrier detected: %s\n", dev, |
| 508 | dev->name); |
| 509 | if (lapb->mode & LAPB_DCE) { |
| 510 | lapb_start_t1timer(lapb); |
| 511 | } else { |
| 512 | if (lapb->state == LAPB_STATE_0) { |
| 513 | lapb->state = LAPB_STATE_1; |
| 514 | lapb_establish_data_link(lapb); |
| 515 | } |
| 516 | } |
| 517 | } else { |
| 518 | lapb_dbg(0, "(%p) Carrier lost: %s\n", dev, dev->name); |
| 519 | lapb_dbg(0, "(%p) S%d -> S0\n", dev, lapb->state); |
| 520 | lapb_clear_queues(lapb); |
| 521 | lapb->state = LAPB_STATE_0; |
| 522 | lapb->n2count = 0; |
| 523 | lapb_stop_t1timer(lapb); |
| 524 | lapb_stop_t2timer(lapb); |
| 525 | } |
| 526 | break; |
| 527 | } |
| 528 | |
Xie He | b491e6a | 2021-01-25 20:09:39 -0800 | [diff] [blame] | 529 | spin_unlock_bh(&lapb->lock); |
Xie He | b40f97b | 2020-12-31 09:43:31 -0800 | [diff] [blame] | 530 | lapb_put(lapb); |
Martin Schiller | a4989fa | 2020-11-26 07:35:54 +0100 | [diff] [blame] | 531 | return NOTIFY_DONE; |
| 532 | } |
| 533 | |
| 534 | static struct notifier_block lapb_dev_notifier = { |
| 535 | .notifier_call = lapb_device_event, |
| 536 | }; |
| 537 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 538 | static int __init lapb_init(void) |
| 539 | { |
Martin Schiller | a4989fa | 2020-11-26 07:35:54 +0100 | [diff] [blame] | 540 | return register_netdevice_notifier(&lapb_dev_notifier); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 541 | } |
| 542 | |
| 543 | static void __exit lapb_exit(void) |
| 544 | { |
| 545 | WARN_ON(!list_empty(&lapb_list)); |
Martin Schiller | a4989fa | 2020-11-26 07:35:54 +0100 | [diff] [blame] | 546 | |
| 547 | unregister_netdevice_notifier(&lapb_dev_notifier); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 548 | } |
| 549 | |
| 550 | MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>"); |
| 551 | MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol"); |
| 552 | MODULE_LICENSE("GPL"); |
| 553 | |
| 554 | module_init(lapb_init); |
| 555 | module_exit(lapb_exit); |