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