18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * LAPB release 002 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This code REQUIRES 2.1.15 or higher/ NET3.038 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * History 88c2ecf20Sopenharmony_ci * LAPB 001 Jonathan Naylor Started Coding 98c2ecf20Sopenharmony_ci * LAPB 002 Jonathan Naylor New timer architecture. 108c2ecf20Sopenharmony_ci * 2000-10-29 Henner Eisen lapb_data_indication() return status. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/socket.h> 198c2ecf20Sopenharmony_ci#include <linux/in.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 228c2ecf20Sopenharmony_ci#include <linux/timer.h> 238c2ecf20Sopenharmony_ci#include <linux/string.h> 248c2ecf20Sopenharmony_ci#include <linux/sockios.h> 258c2ecf20Sopenharmony_ci#include <linux/net.h> 268c2ecf20Sopenharmony_ci#include <linux/inet.h> 278c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 288c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <net/sock.h> 318c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 328c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 338c2ecf20Sopenharmony_ci#include <linux/mm.h> 348c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 358c2ecf20Sopenharmony_ci#include <linux/stat.h> 368c2ecf20Sopenharmony_ci#include <linux/init.h> 378c2ecf20Sopenharmony_ci#include <net/lapb.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic LIST_HEAD(lapb_list); 408c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(lapb_list_lock); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Free an allocated lapb control block. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistatic void lapb_free_cb(struct lapb_cb *lapb) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci kfree(lapb); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic __inline__ void lapb_hold(struct lapb_cb *lapb) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci refcount_inc(&lapb->refcnt); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic __inline__ void lapb_put(struct lapb_cb *lapb) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&lapb->refcnt)) 588c2ecf20Sopenharmony_ci lapb_free_cb(lapb); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * Socket removal during an interrupt is now safe. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic void __lapb_remove_cb(struct lapb_cb *lapb) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci if (lapb->node.next) { 678c2ecf20Sopenharmony_ci list_del(&lapb->node); 688c2ecf20Sopenharmony_ci lapb_put(lapb); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * Add a socket to the bound sockets list. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistatic void __lapb_insert_cb(struct lapb_cb *lapb) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci list_add(&lapb->node, &lapb_list); 788c2ecf20Sopenharmony_ci lapb_hold(lapb); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic struct lapb_cb *__lapb_devtostruct(struct net_device *dev) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct list_head *entry; 848c2ecf20Sopenharmony_ci struct lapb_cb *lapb, *use = NULL; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci list_for_each(entry, &lapb_list) { 878c2ecf20Sopenharmony_ci lapb = list_entry(entry, struct lapb_cb, node); 888c2ecf20Sopenharmony_ci if (lapb->dev == dev) { 898c2ecf20Sopenharmony_ci use = lapb; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (use) 958c2ecf20Sopenharmony_ci lapb_hold(use); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return use; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic struct lapb_cb *lapb_devtostruct(struct net_device *dev) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct lapb_cb *rc; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci read_lock_bh(&lapb_list_lock); 1058c2ecf20Sopenharmony_ci rc = __lapb_devtostruct(dev); 1068c2ecf20Sopenharmony_ci read_unlock_bh(&lapb_list_lock); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return rc; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci/* 1118c2ecf20Sopenharmony_ci * Create an empty LAPB control block. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_cistatic struct lapb_cb *lapb_create_cb(void) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct lapb_cb *lapb = kzalloc(sizeof(*lapb), GFP_ATOMIC); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (!lapb) 1188c2ecf20Sopenharmony_ci goto out; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci skb_queue_head_init(&lapb->write_queue); 1218c2ecf20Sopenharmony_ci skb_queue_head_init(&lapb->ack_queue); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci timer_setup(&lapb->t1timer, NULL, 0); 1248c2ecf20Sopenharmony_ci timer_setup(&lapb->t2timer, NULL, 0); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci lapb->t1 = LAPB_DEFAULT_T1; 1278c2ecf20Sopenharmony_ci lapb->t2 = LAPB_DEFAULT_T2; 1288c2ecf20Sopenharmony_ci lapb->n2 = LAPB_DEFAULT_N2; 1298c2ecf20Sopenharmony_ci lapb->mode = LAPB_DEFAULT_MODE; 1308c2ecf20Sopenharmony_ci lapb->window = LAPB_DEFAULT_WINDOW; 1318c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_0; 1328c2ecf20Sopenharmony_ci refcount_set(&lapb->refcnt, 1); 1338c2ecf20Sopenharmony_ciout: 1348c2ecf20Sopenharmony_ci return lapb; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciint lapb_register(struct net_device *dev, 1388c2ecf20Sopenharmony_ci const struct lapb_register_struct *callbacks) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct lapb_cb *lapb; 1418c2ecf20Sopenharmony_ci int rc = LAPB_BADTOKEN; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci write_lock_bh(&lapb_list_lock); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci lapb = __lapb_devtostruct(dev); 1468c2ecf20Sopenharmony_ci if (lapb) { 1478c2ecf20Sopenharmony_ci lapb_put(lapb); 1488c2ecf20Sopenharmony_ci goto out; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci lapb = lapb_create_cb(); 1528c2ecf20Sopenharmony_ci rc = LAPB_NOMEM; 1538c2ecf20Sopenharmony_ci if (!lapb) 1548c2ecf20Sopenharmony_ci goto out; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci lapb->dev = dev; 1578c2ecf20Sopenharmony_ci lapb->callbacks = callbacks; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci __lapb_insert_cb(lapb); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci rc = LAPB_OK; 1648c2ecf20Sopenharmony_ciout: 1658c2ecf20Sopenharmony_ci write_unlock_bh(&lapb_list_lock); 1668c2ecf20Sopenharmony_ci return rc; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lapb_register); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint lapb_unregister(struct net_device *dev) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct lapb_cb *lapb; 1738c2ecf20Sopenharmony_ci int rc = LAPB_BADTOKEN; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci write_lock_bh(&lapb_list_lock); 1768c2ecf20Sopenharmony_ci lapb = __lapb_devtostruct(dev); 1778c2ecf20Sopenharmony_ci if (!lapb) 1788c2ecf20Sopenharmony_ci goto out; 1798c2ecf20Sopenharmony_ci lapb_put(lapb); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci lapb_stop_t1timer(lapb); 1828c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci lapb_clear_queues(lapb); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci __lapb_remove_cb(lapb); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci lapb_put(lapb); 1898c2ecf20Sopenharmony_ci rc = LAPB_OK; 1908c2ecf20Sopenharmony_ciout: 1918c2ecf20Sopenharmony_ci write_unlock_bh(&lapb_list_lock); 1928c2ecf20Sopenharmony_ci return rc; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lapb_unregister); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ciint lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci int rc = LAPB_BADTOKEN; 1998c2ecf20Sopenharmony_ci struct lapb_cb *lapb = lapb_devtostruct(dev); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!lapb) 2028c2ecf20Sopenharmony_ci goto out; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci parms->t1 = lapb->t1 / HZ; 2058c2ecf20Sopenharmony_ci parms->t2 = lapb->t2 / HZ; 2068c2ecf20Sopenharmony_ci parms->n2 = lapb->n2; 2078c2ecf20Sopenharmony_ci parms->n2count = lapb->n2count; 2088c2ecf20Sopenharmony_ci parms->state = lapb->state; 2098c2ecf20Sopenharmony_ci parms->window = lapb->window; 2108c2ecf20Sopenharmony_ci parms->mode = lapb->mode; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (!timer_pending(&lapb->t1timer)) 2138c2ecf20Sopenharmony_ci parms->t1timer = 0; 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (!timer_pending(&lapb->t2timer)) 2188c2ecf20Sopenharmony_ci parms->t2timer = 0; 2198c2ecf20Sopenharmony_ci else 2208c2ecf20Sopenharmony_ci parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci lapb_put(lapb); 2238c2ecf20Sopenharmony_ci rc = LAPB_OK; 2248c2ecf20Sopenharmony_ciout: 2258c2ecf20Sopenharmony_ci return rc; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lapb_getparms); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciint lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int rc = LAPB_BADTOKEN; 2328c2ecf20Sopenharmony_ci struct lapb_cb *lapb = lapb_devtostruct(dev); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (!lapb) 2358c2ecf20Sopenharmony_ci goto out; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci rc = LAPB_INVALUE; 2388c2ecf20Sopenharmony_ci if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1) 2398c2ecf20Sopenharmony_ci goto out_put; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (lapb->state == LAPB_STATE_0) { 2428c2ecf20Sopenharmony_ci if (parms->mode & LAPB_EXTENDED) { 2438c2ecf20Sopenharmony_ci if (parms->window < 1 || parms->window > 127) 2448c2ecf20Sopenharmony_ci goto out_put; 2458c2ecf20Sopenharmony_ci } else { 2468c2ecf20Sopenharmony_ci if (parms->window < 1 || parms->window > 7) 2478c2ecf20Sopenharmony_ci goto out_put; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci lapb->mode = parms->mode; 2508c2ecf20Sopenharmony_ci lapb->window = parms->window; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci lapb->t1 = parms->t1 * HZ; 2548c2ecf20Sopenharmony_ci lapb->t2 = parms->t2 * HZ; 2558c2ecf20Sopenharmony_ci lapb->n2 = parms->n2; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci rc = LAPB_OK; 2588c2ecf20Sopenharmony_ciout_put: 2598c2ecf20Sopenharmony_ci lapb_put(lapb); 2608c2ecf20Sopenharmony_ciout: 2618c2ecf20Sopenharmony_ci return rc; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lapb_setparms); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ciint lapb_connect_request(struct net_device *dev) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct lapb_cb *lapb = lapb_devtostruct(dev); 2688c2ecf20Sopenharmony_ci int rc = LAPB_BADTOKEN; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (!lapb) 2718c2ecf20Sopenharmony_ci goto out; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci rc = LAPB_OK; 2748c2ecf20Sopenharmony_ci if (lapb->state == LAPB_STATE_1) 2758c2ecf20Sopenharmony_ci goto out_put; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci rc = LAPB_CONNECTED; 2788c2ecf20Sopenharmony_ci if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4) 2798c2ecf20Sopenharmony_ci goto out_put; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci lapb_establish_data_link(lapb); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S0 -> S1\n", lapb->dev); 2848c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_1; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci rc = LAPB_OK; 2878c2ecf20Sopenharmony_ciout_put: 2888c2ecf20Sopenharmony_ci lapb_put(lapb); 2898c2ecf20Sopenharmony_ciout: 2908c2ecf20Sopenharmony_ci return rc; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lapb_connect_request); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciint lapb_disconnect_request(struct net_device *dev) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct lapb_cb *lapb = lapb_devtostruct(dev); 2978c2ecf20Sopenharmony_ci int rc = LAPB_BADTOKEN; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (!lapb) 3008c2ecf20Sopenharmony_ci goto out; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci switch (lapb->state) { 3038c2ecf20Sopenharmony_ci case LAPB_STATE_0: 3048c2ecf20Sopenharmony_ci rc = LAPB_NOTCONNECTED; 3058c2ecf20Sopenharmony_ci goto out_put; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci case LAPB_STATE_1: 3088c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S1 TX DISC(1)\n", lapb->dev); 3098c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev); 3108c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); 3118c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_0; 3128c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 3138c2ecf20Sopenharmony_ci rc = LAPB_NOTCONNECTED; 3148c2ecf20Sopenharmony_ci goto out_put; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci case LAPB_STATE_2: 3178c2ecf20Sopenharmony_ci rc = LAPB_OK; 3188c2ecf20Sopenharmony_ci goto out_put; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci lapb_clear_queues(lapb); 3228c2ecf20Sopenharmony_ci lapb->n2count = 0; 3238c2ecf20Sopenharmony_ci lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); 3248c2ecf20Sopenharmony_ci lapb_start_t1timer(lapb); 3258c2ecf20Sopenharmony_ci lapb_stop_t2timer(lapb); 3268c2ecf20Sopenharmony_ci lapb->state = LAPB_STATE_2; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci lapb_dbg(1, "(%p) S3 DISC(1)\n", lapb->dev); 3298c2ecf20Sopenharmony_ci lapb_dbg(0, "(%p) S3 -> S2\n", lapb->dev); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci rc = LAPB_OK; 3328c2ecf20Sopenharmony_ciout_put: 3338c2ecf20Sopenharmony_ci lapb_put(lapb); 3348c2ecf20Sopenharmony_ciout: 3358c2ecf20Sopenharmony_ci return rc; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lapb_disconnect_request); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ciint lapb_data_request(struct net_device *dev, struct sk_buff *skb) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct lapb_cb *lapb = lapb_devtostruct(dev); 3428c2ecf20Sopenharmony_ci int rc = LAPB_BADTOKEN; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!lapb) 3458c2ecf20Sopenharmony_ci goto out; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci rc = LAPB_NOTCONNECTED; 3488c2ecf20Sopenharmony_ci if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4) 3498c2ecf20Sopenharmony_ci goto out_put; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci skb_queue_tail(&lapb->write_queue, skb); 3528c2ecf20Sopenharmony_ci lapb_kick(lapb); 3538c2ecf20Sopenharmony_ci rc = LAPB_OK; 3548c2ecf20Sopenharmony_ciout_put: 3558c2ecf20Sopenharmony_ci lapb_put(lapb); 3568c2ecf20Sopenharmony_ciout: 3578c2ecf20Sopenharmony_ci return rc; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lapb_data_request); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ciint lapb_data_received(struct net_device *dev, struct sk_buff *skb) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct lapb_cb *lapb = lapb_devtostruct(dev); 3648c2ecf20Sopenharmony_ci int rc = LAPB_BADTOKEN; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (lapb) { 3678c2ecf20Sopenharmony_ci lapb_data_input(lapb, skb); 3688c2ecf20Sopenharmony_ci lapb_put(lapb); 3698c2ecf20Sopenharmony_ci rc = LAPB_OK; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return rc; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(lapb_data_received); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_civoid lapb_connect_confirmation(struct lapb_cb *lapb, int reason) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci if (lapb->callbacks->connect_confirmation) 3798c2ecf20Sopenharmony_ci lapb->callbacks->connect_confirmation(lapb->dev, reason); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_civoid lapb_connect_indication(struct lapb_cb *lapb, int reason) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci if (lapb->callbacks->connect_indication) 3858c2ecf20Sopenharmony_ci lapb->callbacks->connect_indication(lapb->dev, reason); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_civoid lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci if (lapb->callbacks->disconnect_confirmation) 3918c2ecf20Sopenharmony_ci lapb->callbacks->disconnect_confirmation(lapb->dev, reason); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_civoid lapb_disconnect_indication(struct lapb_cb *lapb, int reason) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci if (lapb->callbacks->disconnect_indication) 3978c2ecf20Sopenharmony_ci lapb->callbacks->disconnect_indication(lapb->dev, reason); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ciint lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci if (lapb->callbacks->data_indication) 4038c2ecf20Sopenharmony_ci return lapb->callbacks->data_indication(lapb->dev, skb); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci kfree_skb(skb); 4068c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */ 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ciint lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci int used = 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (lapb->callbacks->data_transmit) { 4148c2ecf20Sopenharmony_ci lapb->callbacks->data_transmit(lapb->dev, skb); 4158c2ecf20Sopenharmony_ci used = 1; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return used; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int __init lapb_init(void) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic void __exit lapb_exit(void) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&lapb_list)); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>"); 4328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol"); 4338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cimodule_init(lapb_init); 4368c2ecf20Sopenharmony_cimodule_exit(lapb_exit); 437