1 /* 2 * LAPB release 002 3 * 4 * This code REQUIRES 2.1.15 or higher/ NET3.038 5 * 6 * This module: 7 * This module is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 10 * 2 of the License, or (at your option) any later version. 11 * 12 * History 13 * LAPB 001 Jonathan Naylor Started Coding 14 * LAPB 002 Jonathan Naylor New timer architecture. 15 * 2000-10-29 Henner Eisen lapb_data_indication() return status. 16 */ 17 18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 20 #include <linux/module.h> 21 #include <linux/errno.h> 22 #include <linux/types.h> 23 #include <linux/socket.h> 24 #include <linux/in.h> 25 #include <linux/kernel.h> 26 #include <linux/jiffies.h> 27 #include <linux/timer.h> 28 #include <linux/string.h> 29 #include <linux/sockios.h> 30 #include <linux/net.h> 31 #include <linux/inet.h> 32 #include <linux/if_arp.h> 33 #include <linux/skbuff.h> 34 #include <linux/slab.h> 35 #include <net/sock.h> 36 #include <asm/uaccess.h> 37 #include <linux/fcntl.h> 38 #include <linux/mm.h> 39 #include <linux/interrupt.h> 40 #include <linux/stat.h> 41 #include <linux/init.h> 42 #include <net/lapb.h> 43 44 static LIST_HEAD(lapb_list); 45 static DEFINE_RWLOCK(lapb_list_lock); 46 47 /* 48 * Free an allocated lapb control block. 49 */ 50 static void lapb_free_cb(struct lapb_cb *lapb) 51 { 52 kfree(lapb); 53 } 54 55 static __inline__ void lapb_hold(struct lapb_cb *lapb) 56 { 57 atomic_inc(&lapb->refcnt); 58 } 59 60 static __inline__ void lapb_put(struct lapb_cb *lapb) 61 { 62 if (atomic_dec_and_test(&lapb->refcnt)) 63 lapb_free_cb(lapb); 64 } 65 66 /* 67 * Socket removal during an interrupt is now safe. 68 */ 69 static void __lapb_remove_cb(struct lapb_cb *lapb) 70 { 71 if (lapb->node.next) { 72 list_del(&lapb->node); 73 lapb_put(lapb); 74 } 75 } 76 77 /* 78 * Add a socket to the bound sockets list. 79 */ 80 static void __lapb_insert_cb(struct lapb_cb *lapb) 81 { 82 list_add(&lapb->node, &lapb_list); 83 lapb_hold(lapb); 84 } 85 86 static struct lapb_cb *__lapb_devtostruct(struct net_device *dev) 87 { 88 struct list_head *entry; 89 struct lapb_cb *lapb, *use = NULL; 90 91 list_for_each(entry, &lapb_list) { 92 lapb = list_entry(entry, struct lapb_cb, node); 93 if (lapb->dev == dev) { 94 use = lapb; 95 break; 96 } 97 } 98 99 if (use) 100 lapb_hold(use); 101 102 return use; 103 } 104 105 static struct lapb_cb *lapb_devtostruct(struct net_device *dev) 106 { 107 struct lapb_cb *rc; 108 109 read_lock_bh(&lapb_list_lock); 110 rc = __lapb_devtostruct(dev); 111 read_unlock_bh(&lapb_list_lock); 112 113 return rc; 114 } 115 /* 116 * Create an empty LAPB control block. 117 */ 118 static struct lapb_cb *lapb_create_cb(void) 119 { 120 struct lapb_cb *lapb = kzalloc(sizeof(*lapb), GFP_ATOMIC); 121 122 123 if (!lapb) 124 goto out; 125 126 skb_queue_head_init(&lapb->write_queue); 127 skb_queue_head_init(&lapb->ack_queue); 128 129 init_timer(&lapb->t1timer); 130 init_timer(&lapb->t2timer); 131 132 lapb->t1 = LAPB_DEFAULT_T1; 133 lapb->t2 = LAPB_DEFAULT_T2; 134 lapb->n2 = LAPB_DEFAULT_N2; 135 lapb->mode = LAPB_DEFAULT_MODE; 136 lapb->window = LAPB_DEFAULT_WINDOW; 137 lapb->state = LAPB_STATE_0; 138 atomic_set(&lapb->refcnt, 1); 139 out: 140 return lapb; 141 } 142 143 int lapb_register(struct net_device *dev, 144 const struct lapb_register_struct *callbacks) 145 { 146 struct lapb_cb *lapb; 147 int rc = LAPB_BADTOKEN; 148 149 write_lock_bh(&lapb_list_lock); 150 151 lapb = __lapb_devtostruct(dev); 152 if (lapb) { 153 lapb_put(lapb); 154 goto out; 155 } 156 157 lapb = lapb_create_cb(); 158 rc = LAPB_NOMEM; 159 if (!lapb) 160 goto out; 161 162 lapb->dev = dev; 163 lapb->callbacks = callbacks; 164 165 __lapb_insert_cb(lapb); 166 167 lapb_start_t1timer(lapb); 168 169 rc = LAPB_OK; 170 out: 171 write_unlock_bh(&lapb_list_lock); 172 return rc; 173 } 174 175 int lapb_unregister(struct net_device *dev) 176 { 177 struct lapb_cb *lapb; 178 int rc = LAPB_BADTOKEN; 179 180 write_lock_bh(&lapb_list_lock); 181 lapb = __lapb_devtostruct(dev); 182 if (!lapb) 183 goto out; 184 185 lapb_stop_t1timer(lapb); 186 lapb_stop_t2timer(lapb); 187 188 lapb_clear_queues(lapb); 189 190 __lapb_remove_cb(lapb); 191 192 lapb_put(lapb); 193 rc = LAPB_OK; 194 out: 195 write_unlock_bh(&lapb_list_lock); 196 return rc; 197 } 198 199 int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms) 200 { 201 int rc = LAPB_BADTOKEN; 202 struct lapb_cb *lapb = lapb_devtostruct(dev); 203 204 if (!lapb) 205 goto out; 206 207 parms->t1 = lapb->t1 / HZ; 208 parms->t2 = lapb->t2 / HZ; 209 parms->n2 = lapb->n2; 210 parms->n2count = lapb->n2count; 211 parms->state = lapb->state; 212 parms->window = lapb->window; 213 parms->mode = lapb->mode; 214 215 if (!timer_pending(&lapb->t1timer)) 216 parms->t1timer = 0; 217 else 218 parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ; 219 220 if (!timer_pending(&lapb->t2timer)) 221 parms->t2timer = 0; 222 else 223 parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ; 224 225 lapb_put(lapb); 226 rc = LAPB_OK; 227 out: 228 return rc; 229 } 230 231 int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms) 232 { 233 int rc = LAPB_BADTOKEN; 234 struct lapb_cb *lapb = lapb_devtostruct(dev); 235 236 if (!lapb) 237 goto out; 238 239 rc = LAPB_INVALUE; 240 if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1) 241 goto out_put; 242 243 if (lapb->state == LAPB_STATE_0) { 244 if (parms->mode & LAPB_EXTENDED) { 245 if (parms->window < 1 || parms->window > 127) 246 goto out_put; 247 } else { 248 if (parms->window < 1 || parms->window > 7) 249 goto out_put; 250 } 251 lapb->mode = parms->mode; 252 lapb->window = parms->window; 253 } 254 255 lapb->t1 = parms->t1 * HZ; 256 lapb->t2 = parms->t2 * HZ; 257 lapb->n2 = parms->n2; 258 259 rc = LAPB_OK; 260 out_put: 261 lapb_put(lapb); 262 out: 263 return rc; 264 } 265 266 int lapb_connect_request(struct net_device *dev) 267 { 268 struct lapb_cb *lapb = lapb_devtostruct(dev); 269 int rc = LAPB_BADTOKEN; 270 271 if (!lapb) 272 goto out; 273 274 rc = LAPB_OK; 275 if (lapb->state == LAPB_STATE_1) 276 goto out_put; 277 278 rc = LAPB_CONNECTED; 279 if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4) 280 goto out_put; 281 282 lapb_establish_data_link(lapb); 283 284 lapb_dbg(0, "(%p) S0 -> S1\n", lapb->dev); 285 lapb->state = LAPB_STATE_1; 286 287 rc = LAPB_OK; 288 out_put: 289 lapb_put(lapb); 290 out: 291 return rc; 292 } 293 294 int lapb_disconnect_request(struct net_device *dev) 295 { 296 struct lapb_cb *lapb = lapb_devtostruct(dev); 297 int rc = LAPB_BADTOKEN; 298 299 if (!lapb) 300 goto out; 301 302 switch (lapb->state) { 303 case LAPB_STATE_0: 304 rc = LAPB_NOTCONNECTED; 305 goto out_put; 306 307 case LAPB_STATE_1: 308 lapb_dbg(1, "(%p) S1 TX DISC(1)\n", lapb->dev); 309 lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev); 310 lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); 311 lapb->state = LAPB_STATE_0; 312 lapb_start_t1timer(lapb); 313 rc = LAPB_NOTCONNECTED; 314 goto out_put; 315 316 case LAPB_STATE_2: 317 rc = LAPB_OK; 318 goto out_put; 319 } 320 321 lapb_clear_queues(lapb); 322 lapb->n2count = 0; 323 lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); 324 lapb_start_t1timer(lapb); 325 lapb_stop_t2timer(lapb); 326 lapb->state = LAPB_STATE_2; 327 328 lapb_dbg(1, "(%p) S3 DISC(1)\n", lapb->dev); 329 lapb_dbg(0, "(%p) S3 -> S2\n", lapb->dev); 330 331 rc = LAPB_OK; 332 out_put: 333 lapb_put(lapb); 334 out: 335 return rc; 336 } 337 338 int lapb_data_request(struct net_device *dev, struct sk_buff *skb) 339 { 340 struct lapb_cb *lapb = lapb_devtostruct(dev); 341 int rc = LAPB_BADTOKEN; 342 343 if (!lapb) 344 goto out; 345 346 rc = LAPB_NOTCONNECTED; 347 if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4) 348 goto out_put; 349 350 skb_queue_tail(&lapb->write_queue, skb); 351 lapb_kick(lapb); 352 rc = LAPB_OK; 353 out_put: 354 lapb_put(lapb); 355 out: 356 return rc; 357 } 358 359 int lapb_data_received(struct net_device *dev, struct sk_buff *skb) 360 { 361 struct lapb_cb *lapb = lapb_devtostruct(dev); 362 int rc = LAPB_BADTOKEN; 363 364 if (lapb) { 365 lapb_data_input(lapb, skb); 366 lapb_put(lapb); 367 rc = LAPB_OK; 368 } 369 370 return rc; 371 } 372 373 void lapb_connect_confirmation(struct lapb_cb *lapb, int reason) 374 { 375 if (lapb->callbacks->connect_confirmation) 376 lapb->callbacks->connect_confirmation(lapb->dev, reason); 377 } 378 379 void lapb_connect_indication(struct lapb_cb *lapb, int reason) 380 { 381 if (lapb->callbacks->connect_indication) 382 lapb->callbacks->connect_indication(lapb->dev, reason); 383 } 384 385 void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason) 386 { 387 if (lapb->callbacks->disconnect_confirmation) 388 lapb->callbacks->disconnect_confirmation(lapb->dev, reason); 389 } 390 391 void lapb_disconnect_indication(struct lapb_cb *lapb, int reason) 392 { 393 if (lapb->callbacks->disconnect_indication) 394 lapb->callbacks->disconnect_indication(lapb->dev, reason); 395 } 396 397 int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb) 398 { 399 if (lapb->callbacks->data_indication) 400 return lapb->callbacks->data_indication(lapb->dev, skb); 401 402 kfree_skb(skb); 403 return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */ 404 } 405 406 int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb) 407 { 408 int used = 0; 409 410 if (lapb->callbacks->data_transmit) { 411 lapb->callbacks->data_transmit(lapb->dev, skb); 412 used = 1; 413 } 414 415 return used; 416 } 417 418 EXPORT_SYMBOL(lapb_register); 419 EXPORT_SYMBOL(lapb_unregister); 420 EXPORT_SYMBOL(lapb_getparms); 421 EXPORT_SYMBOL(lapb_setparms); 422 EXPORT_SYMBOL(lapb_connect_request); 423 EXPORT_SYMBOL(lapb_disconnect_request); 424 EXPORT_SYMBOL(lapb_data_request); 425 EXPORT_SYMBOL(lapb_data_received); 426 427 static int __init lapb_init(void) 428 { 429 return 0; 430 } 431 432 static void __exit lapb_exit(void) 433 { 434 WARN_ON(!list_empty(&lapb_list)); 435 } 436 437 MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>"); 438 MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol"); 439 MODULE_LICENSE("GPL"); 440 441 module_init(lapb_init); 442 module_exit(lapb_exit); 443