18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Generic HDLC support routines for Linux 48c2ecf20Sopenharmony_ci * X.25 support 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/gfp.h> 118c2ecf20Sopenharmony_ci#include <linux/hdlc.h> 128c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 138c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/lapb.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/pkt_sched.h> 198c2ecf20Sopenharmony_ci#include <linux/poll.h> 208c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 218c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 228c2ecf20Sopenharmony_ci#include <net/x25device.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct x25_state { 258c2ecf20Sopenharmony_ci x25_hdlc_proto settings; 268c2ecf20Sopenharmony_ci bool up; 278c2ecf20Sopenharmony_ci spinlock_t up_lock; /* Protects "up" */ 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int x25_ioctl(struct net_device *dev, struct ifreq *ifr); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct x25_state *state(hdlc_device *hdlc) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci return hdlc->state; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* These functions are callbacks called by LAPB layer */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void x25_connect_disconnect(struct net_device *dev, int reason, int code) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct sk_buff *skb; 428c2ecf20Sopenharmony_ci unsigned char *ptr; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if ((skb = dev_alloc_skb(1)) == NULL) { 458c2ecf20Sopenharmony_ci netdev_err(dev, "out of memory\n"); 468c2ecf20Sopenharmony_ci return; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci ptr = skb_put(skb, 1); 508c2ecf20Sopenharmony_ci *ptr = code; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci skb->protocol = x25_type_trans(skb, dev); 538c2ecf20Sopenharmony_ci netif_rx(skb); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void x25_connected(struct net_device *dev, int reason) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci x25_connect_disconnect(dev, reason, X25_IFACE_CONNECT); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void x25_disconnected(struct net_device *dev, int reason) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci x25_connect_disconnect(dev, reason, X25_IFACE_DISCONNECT); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int x25_data_indication(struct net_device *dev, struct sk_buff *skb) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci unsigned char *ptr; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (skb_cow(skb, 1)) { 778c2ecf20Sopenharmony_ci kfree_skb(skb); 788c2ecf20Sopenharmony_ci return NET_RX_DROP; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci skb_push(skb, 1); 828c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ptr = skb->data; 858c2ecf20Sopenharmony_ci *ptr = X25_IFACE_DATA; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci skb->protocol = x25_type_trans(skb, dev); 888c2ecf20Sopenharmony_ci return netif_rx(skb); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void x25_data_transmit(struct net_device *dev, struct sk_buff *skb) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci hdlc_device *hdlc = dev_to_hdlc(dev); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 988c2ecf20Sopenharmony_ci skb->protocol = hdlc_type_trans(skb, dev); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (dev_nit_active(dev)) 1018c2ecf20Sopenharmony_ci dev_queue_xmit_nit(skb, dev); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci hdlc->xmit(skb, dev); /* Ignore return value :-( */ 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci hdlc_device *hdlc = dev_to_hdlc(dev); 1118c2ecf20Sopenharmony_ci struct x25_state *x25st = state(hdlc); 1128c2ecf20Sopenharmony_ci int result; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* There should be a pseudo header of 1 byte added by upper layers. 1158c2ecf20Sopenharmony_ci * Check to make sure it is there before reading it. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci if (skb->len < 1) { 1188c2ecf20Sopenharmony_ci kfree_skb(skb); 1198c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci spin_lock_bh(&x25st->up_lock); 1238c2ecf20Sopenharmony_ci if (!x25st->up) { 1248c2ecf20Sopenharmony_ci spin_unlock_bh(&x25st->up_lock); 1258c2ecf20Sopenharmony_ci kfree_skb(skb); 1268c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci switch (skb->data[0]) { 1308c2ecf20Sopenharmony_ci case X25_IFACE_DATA: /* Data to be transmitted */ 1318c2ecf20Sopenharmony_ci skb_pull(skb, 1); 1328c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 1338c2ecf20Sopenharmony_ci if ((result = lapb_data_request(dev, skb)) != LAPB_OK) 1348c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 1358c2ecf20Sopenharmony_ci spin_unlock_bh(&x25st->up_lock); 1368c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci case X25_IFACE_CONNECT: 1398c2ecf20Sopenharmony_ci if ((result = lapb_connect_request(dev))!= LAPB_OK) { 1408c2ecf20Sopenharmony_ci if (result == LAPB_CONNECTED) 1418c2ecf20Sopenharmony_ci /* Send connect confirm. msg to level 3 */ 1428c2ecf20Sopenharmony_ci x25_connected(dev, 0); 1438c2ecf20Sopenharmony_ci else 1448c2ecf20Sopenharmony_ci netdev_err(dev, "LAPB connect request failed, error code = %i\n", 1458c2ecf20Sopenharmony_ci result); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci case X25_IFACE_DISCONNECT: 1508c2ecf20Sopenharmony_ci if ((result = lapb_disconnect_request(dev)) != LAPB_OK) { 1518c2ecf20Sopenharmony_ci if (result == LAPB_NOTCONNECTED) 1528c2ecf20Sopenharmony_ci /* Send disconnect confirm. msg to level 3 */ 1538c2ecf20Sopenharmony_ci x25_disconnected(dev, 0); 1548c2ecf20Sopenharmony_ci else 1558c2ecf20Sopenharmony_ci netdev_err(dev, "LAPB disconnect request failed, error code = %i\n", 1568c2ecf20Sopenharmony_ci result); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci default: /* to be defined */ 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci spin_unlock_bh(&x25st->up_lock); 1658c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 1668c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int x25_open(struct net_device *dev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci static const struct lapb_register_struct cb = { 1748c2ecf20Sopenharmony_ci .connect_confirmation = x25_connected, 1758c2ecf20Sopenharmony_ci .connect_indication = x25_connected, 1768c2ecf20Sopenharmony_ci .disconnect_confirmation = x25_disconnected, 1778c2ecf20Sopenharmony_ci .disconnect_indication = x25_disconnected, 1788c2ecf20Sopenharmony_ci .data_indication = x25_data_indication, 1798c2ecf20Sopenharmony_ci .data_transmit = x25_data_transmit, 1808c2ecf20Sopenharmony_ci }; 1818c2ecf20Sopenharmony_ci hdlc_device *hdlc = dev_to_hdlc(dev); 1828c2ecf20Sopenharmony_ci struct x25_state *x25st = state(hdlc); 1838c2ecf20Sopenharmony_ci struct lapb_parms_struct params; 1848c2ecf20Sopenharmony_ci int result; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci result = lapb_register(dev, &cb); 1878c2ecf20Sopenharmony_ci if (result != LAPB_OK) 1888c2ecf20Sopenharmony_ci return -ENOMEM; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci result = lapb_getparms(dev, ¶ms); 1918c2ecf20Sopenharmony_ci if (result != LAPB_OK) 1928c2ecf20Sopenharmony_ci return -EINVAL; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (state(hdlc)->settings.dce) 1958c2ecf20Sopenharmony_ci params.mode = params.mode | LAPB_DCE; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (state(hdlc)->settings.modulo == 128) 1988c2ecf20Sopenharmony_ci params.mode = params.mode | LAPB_EXTENDED; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci params.window = state(hdlc)->settings.window; 2018c2ecf20Sopenharmony_ci params.t1 = state(hdlc)->settings.t1; 2028c2ecf20Sopenharmony_ci params.t2 = state(hdlc)->settings.t2; 2038c2ecf20Sopenharmony_ci params.n2 = state(hdlc)->settings.n2; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci result = lapb_setparms(dev, ¶ms); 2068c2ecf20Sopenharmony_ci if (result != LAPB_OK) 2078c2ecf20Sopenharmony_ci return -EINVAL; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci spin_lock_bh(&x25st->up_lock); 2108c2ecf20Sopenharmony_ci x25st->up = true; 2118c2ecf20Sopenharmony_ci spin_unlock_bh(&x25st->up_lock); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic void x25_close(struct net_device *dev) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci hdlc_device *hdlc = dev_to_hdlc(dev); 2218c2ecf20Sopenharmony_ci struct x25_state *x25st = state(hdlc); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci spin_lock_bh(&x25st->up_lock); 2248c2ecf20Sopenharmony_ci x25st->up = false; 2258c2ecf20Sopenharmony_ci spin_unlock_bh(&x25st->up_lock); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci lapb_unregister(dev); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int x25_rx(struct sk_buff *skb) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct net_device *dev = skb->dev; 2358c2ecf20Sopenharmony_ci hdlc_device *hdlc = dev_to_hdlc(dev); 2368c2ecf20Sopenharmony_ci struct x25_state *x25st = state(hdlc); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { 2398c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 2408c2ecf20Sopenharmony_ci return NET_RX_DROP; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci spin_lock_bh(&x25st->up_lock); 2448c2ecf20Sopenharmony_ci if (!x25st->up) { 2458c2ecf20Sopenharmony_ci spin_unlock_bh(&x25st->up_lock); 2468c2ecf20Sopenharmony_ci kfree_skb(skb); 2478c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 2488c2ecf20Sopenharmony_ci return NET_RX_DROP; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (lapb_data_received(dev, skb) == LAPB_OK) { 2528c2ecf20Sopenharmony_ci spin_unlock_bh(&x25st->up_lock); 2538c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci spin_unlock_bh(&x25st->up_lock); 2578c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 2588c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2598c2ecf20Sopenharmony_ci return NET_RX_DROP; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic struct hdlc_proto proto = { 2648c2ecf20Sopenharmony_ci .open = x25_open, 2658c2ecf20Sopenharmony_ci .close = x25_close, 2668c2ecf20Sopenharmony_ci .ioctl = x25_ioctl, 2678c2ecf20Sopenharmony_ci .netif_rx = x25_rx, 2688c2ecf20Sopenharmony_ci .xmit = x25_xmit, 2698c2ecf20Sopenharmony_ci .module = THIS_MODULE, 2708c2ecf20Sopenharmony_ci}; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int x25_ioctl(struct net_device *dev, struct ifreq *ifr) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci x25_hdlc_proto __user *x25_s = ifr->ifr_settings.ifs_ifsu.x25; 2768c2ecf20Sopenharmony_ci const size_t size = sizeof(x25_hdlc_proto); 2778c2ecf20Sopenharmony_ci hdlc_device *hdlc = dev_to_hdlc(dev); 2788c2ecf20Sopenharmony_ci x25_hdlc_proto new_settings; 2798c2ecf20Sopenharmony_ci int result; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci switch (ifr->ifr_settings.type) { 2828c2ecf20Sopenharmony_ci case IF_GET_PROTO: 2838c2ecf20Sopenharmony_ci if (dev_to_hdlc(dev)->proto != &proto) 2848c2ecf20Sopenharmony_ci return -EINVAL; 2858c2ecf20Sopenharmony_ci ifr->ifr_settings.type = IF_PROTO_X25; 2868c2ecf20Sopenharmony_ci if (ifr->ifr_settings.size < size) { 2878c2ecf20Sopenharmony_ci ifr->ifr_settings.size = size; /* data size wanted */ 2888c2ecf20Sopenharmony_ci return -ENOBUFS; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci if (copy_to_user(x25_s, &state(hdlc)->settings, size)) 2918c2ecf20Sopenharmony_ci return -EFAULT; 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci case IF_PROTO_X25: 2958c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 2968c2ecf20Sopenharmony_ci return -EPERM; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (dev->flags & IFF_UP) 2998c2ecf20Sopenharmony_ci return -EBUSY; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* backward compatibility */ 3028c2ecf20Sopenharmony_ci if (ifr->ifr_settings.size == 0) { 3038c2ecf20Sopenharmony_ci new_settings.dce = 0; 3048c2ecf20Sopenharmony_ci new_settings.modulo = 8; 3058c2ecf20Sopenharmony_ci new_settings.window = 7; 3068c2ecf20Sopenharmony_ci new_settings.t1 = 3; 3078c2ecf20Sopenharmony_ci new_settings.t2 = 1; 3088c2ecf20Sopenharmony_ci new_settings.n2 = 10; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci else { 3118c2ecf20Sopenharmony_ci if (copy_from_user(&new_settings, x25_s, size)) 3128c2ecf20Sopenharmony_ci return -EFAULT; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if ((new_settings.dce != 0 && 3158c2ecf20Sopenharmony_ci new_settings.dce != 1) || 3168c2ecf20Sopenharmony_ci (new_settings.modulo != 8 && 3178c2ecf20Sopenharmony_ci new_settings.modulo != 128) || 3188c2ecf20Sopenharmony_ci new_settings.window < 1 || 3198c2ecf20Sopenharmony_ci (new_settings.modulo == 8 && 3208c2ecf20Sopenharmony_ci new_settings.window > 7) || 3218c2ecf20Sopenharmony_ci (new_settings.modulo == 128 && 3228c2ecf20Sopenharmony_ci new_settings.window > 127) || 3238c2ecf20Sopenharmony_ci new_settings.t1 < 1 || 3248c2ecf20Sopenharmony_ci new_settings.t1 > 255 || 3258c2ecf20Sopenharmony_ci new_settings.t2 < 1 || 3268c2ecf20Sopenharmony_ci new_settings.t2 > 255 || 3278c2ecf20Sopenharmony_ci new_settings.n2 < 1 || 3288c2ecf20Sopenharmony_ci new_settings.n2 > 255) 3298c2ecf20Sopenharmony_ci return -EINVAL; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); 3338c2ecf20Sopenharmony_ci if (result) 3348c2ecf20Sopenharmony_ci return result; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if ((result = attach_hdlc_protocol(dev, &proto, 3378c2ecf20Sopenharmony_ci sizeof(struct x25_state)))) 3388c2ecf20Sopenharmony_ci return result; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci memcpy(&state(hdlc)->settings, &new_settings, size); 3418c2ecf20Sopenharmony_ci state(hdlc)->up = false; 3428c2ecf20Sopenharmony_ci spin_lock_init(&state(hdlc)->up_lock); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* There's no header_ops so hard_header_len should be 0. */ 3458c2ecf20Sopenharmony_ci dev->hard_header_len = 0; 3468c2ecf20Sopenharmony_ci /* When transmitting data: 3478c2ecf20Sopenharmony_ci * first we'll remove a pseudo header of 1 byte, 3488c2ecf20Sopenharmony_ci * then we'll prepend an LAPB header of at most 3 bytes. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci dev->needed_headroom = 3 - 1; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci dev->type = ARPHRD_X25; 3538c2ecf20Sopenharmony_ci call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev); 3548c2ecf20Sopenharmony_ci netif_dormant_off(dev); 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return -EINVAL; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int __init mod_init(void) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci register_hdlc_protocol(&proto); 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic void __exit mod_exit(void) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci unregister_hdlc_protocol(&proto); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cimodule_init(mod_init); 3778c2ecf20Sopenharmony_cimodule_exit(mod_exit); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ciMODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); 3808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("X.25 protocol support for generic HDLC"); 3818c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 382