11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * LAPB release 002 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This code REQUIRES 2.1.15 or higher/ NET3.038 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This module: 71da177e4SLinus Torvalds * This module is free software; you can redistribute it and/or 81da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 91da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 101da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * History 131da177e4SLinus Torvalds * LAPB 001 Jonathan Naylor Started Coding 141da177e4SLinus Torvalds * LAPB 002 Jonathan Naylor New timer architecture. 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 17a508da6cSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 18a508da6cSJoe Perches 191da177e4SLinus Torvalds #include <linux/errno.h> 201da177e4SLinus Torvalds #include <linux/types.h> 211da177e4SLinus Torvalds #include <linux/socket.h> 221da177e4SLinus Torvalds #include <linux/in.h> 231da177e4SLinus Torvalds #include <linux/kernel.h> 241da177e4SLinus Torvalds #include <linux/jiffies.h> 251da177e4SLinus Torvalds #include <linux/timer.h> 261da177e4SLinus Torvalds #include <linux/string.h> 271da177e4SLinus Torvalds #include <linux/sockios.h> 281da177e4SLinus Torvalds #include <linux/net.h> 291da177e4SLinus Torvalds #include <linux/inet.h> 301da177e4SLinus Torvalds #include <linux/skbuff.h> 311da177e4SLinus Torvalds #include <net/sock.h> 327c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 331da177e4SLinus Torvalds #include <linux/fcntl.h> 341da177e4SLinus Torvalds #include <linux/mm.h> 351da177e4SLinus Torvalds #include <linux/interrupt.h> 361da177e4SLinus Torvalds #include <net/lapb.h> 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds static void lapb_t1timer_expiry(unsigned long); 391da177e4SLinus Torvalds static void lapb_t2timer_expiry(unsigned long); 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds void lapb_start_t1timer(struct lapb_cb *lapb) 421da177e4SLinus Torvalds { 431da177e4SLinus Torvalds del_timer(&lapb->t1timer); 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds lapb->t1timer.data = (unsigned long)lapb; 461da177e4SLinus Torvalds lapb->t1timer.function = &lapb_t1timer_expiry; 471da177e4SLinus Torvalds lapb->t1timer.expires = jiffies + lapb->t1; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds add_timer(&lapb->t1timer); 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds void lapb_start_t2timer(struct lapb_cb *lapb) 531da177e4SLinus Torvalds { 541da177e4SLinus Torvalds del_timer(&lapb->t2timer); 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds lapb->t2timer.data = (unsigned long)lapb; 571da177e4SLinus Torvalds lapb->t2timer.function = &lapb_t2timer_expiry; 581da177e4SLinus Torvalds lapb->t2timer.expires = jiffies + lapb->t2; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds add_timer(&lapb->t2timer); 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds void lapb_stop_t1timer(struct lapb_cb *lapb) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds del_timer(&lapb->t1timer); 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds void lapb_stop_t2timer(struct lapb_cb *lapb) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds del_timer(&lapb->t2timer); 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds int lapb_t1timer_running(struct lapb_cb *lapb) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds return timer_pending(&lapb->t1timer); 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds static void lapb_t2timer_expiry(unsigned long param) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds struct lapb_cb *lapb = (struct lapb_cb *)param; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds if (lapb->condition & LAPB_ACK_PENDING_CONDITION) { 831da177e4SLinus Torvalds lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 841da177e4SLinus Torvalds lapb_timeout_response(lapb); 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds static void lapb_t1timer_expiry(unsigned long param) 891da177e4SLinus Torvalds { 901da177e4SLinus Torvalds struct lapb_cb *lapb = (struct lapb_cb *)param; 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds switch (lapb->state) { 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds /* 951da177e4SLinus Torvalds * If we are a DCE, keep going DM .. DM .. DM 961da177e4SLinus Torvalds */ 971da177e4SLinus Torvalds case LAPB_STATE_0: 981da177e4SLinus Torvalds if (lapb->mode & LAPB_DCE) 991da177e4SLinus Torvalds lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE); 1001da177e4SLinus Torvalds break; 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds /* 1031da177e4SLinus Torvalds * Awaiting connection state, send SABM(E), up to N2 times. 1041da177e4SLinus Torvalds */ 1051da177e4SLinus Torvalds case LAPB_STATE_1: 1061da177e4SLinus Torvalds if (lapb->n2count == lapb->n2) { 1071da177e4SLinus Torvalds lapb_clear_queues(lapb); 1081da177e4SLinus Torvalds lapb->state = LAPB_STATE_0; 1091da177e4SLinus Torvalds lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); 110a508da6cSJoe Perches lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev); 1111da177e4SLinus Torvalds return; 1121da177e4SLinus Torvalds } else { 1131da177e4SLinus Torvalds lapb->n2count++; 1141da177e4SLinus Torvalds if (lapb->mode & LAPB_EXTENDED) { 115a508da6cSJoe Perches lapb_dbg(1, "(%p) S1 TX SABME(1)\n", 116a508da6cSJoe Perches lapb->dev); 1171da177e4SLinus Torvalds lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); 1181da177e4SLinus Torvalds } else { 119a508da6cSJoe Perches lapb_dbg(1, "(%p) S1 TX SABM(1)\n", 120a508da6cSJoe Perches lapb->dev); 1211da177e4SLinus Torvalds lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds break; 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds /* 1271da177e4SLinus Torvalds * Awaiting disconnection state, send DISC, up to N2 times. 1281da177e4SLinus Torvalds */ 1291da177e4SLinus Torvalds case LAPB_STATE_2: 1301da177e4SLinus Torvalds if (lapb->n2count == lapb->n2) { 1311da177e4SLinus Torvalds lapb_clear_queues(lapb); 1321da177e4SLinus Torvalds lapb->state = LAPB_STATE_0; 1331da177e4SLinus Torvalds lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT); 134a508da6cSJoe Perches lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev); 1351da177e4SLinus Torvalds return; 1361da177e4SLinus Torvalds } else { 1371da177e4SLinus Torvalds lapb->n2count++; 138a508da6cSJoe Perches lapb_dbg(1, "(%p) S2 TX DISC(1)\n", lapb->dev); 1391da177e4SLinus Torvalds lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds break; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds /* 1441da177e4SLinus Torvalds * Data transfer state, restransmit I frames, up to N2 times. 1451da177e4SLinus Torvalds */ 1461da177e4SLinus Torvalds case LAPB_STATE_3: 1471da177e4SLinus Torvalds if (lapb->n2count == lapb->n2) { 1481da177e4SLinus Torvalds lapb_clear_queues(lapb); 1491da177e4SLinus Torvalds lapb->state = LAPB_STATE_0; 1501da177e4SLinus Torvalds lapb_stop_t2timer(lapb); 1511da177e4SLinus Torvalds lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); 152a508da6cSJoe Perches lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev); 1531da177e4SLinus Torvalds return; 1541da177e4SLinus Torvalds } else { 1551da177e4SLinus Torvalds lapb->n2count++; 1561da177e4SLinus Torvalds lapb_requeue_frames(lapb); 157a224bd36Sjosselin.costanzi@mobile-devices.fr lapb_kick(lapb); 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds break; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* 1621da177e4SLinus Torvalds * Frame reject state, restransmit FRMR frames, up to N2 times. 1631da177e4SLinus Torvalds */ 1641da177e4SLinus Torvalds case LAPB_STATE_4: 1651da177e4SLinus Torvalds if (lapb->n2count == lapb->n2) { 1661da177e4SLinus Torvalds lapb_clear_queues(lapb); 1671da177e4SLinus Torvalds lapb->state = LAPB_STATE_0; 1681da177e4SLinus Torvalds lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); 169a508da6cSJoe Perches lapb_dbg(0, "(%p) S4 -> S0\n", lapb->dev); 1701da177e4SLinus Torvalds return; 1711da177e4SLinus Torvalds } else { 1721da177e4SLinus Torvalds lapb->n2count++; 1731da177e4SLinus Torvalds lapb_transmit_frmr(lapb); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds break; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds lapb_start_t1timer(lapb); 1791da177e4SLinus Torvalds } 180