385 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Generic HDLC support routines for Linux4 * X.25 support5 *6 * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>7 */8 9#include <linux/errno.h>10#include <linux/gfp.h>11#include <linux/hdlc.h>12#include <linux/if_arp.h>13#include <linux/inetdevice.h>14#include <linux/init.h>15#include <linux/kernel.h>16#include <linux/lapb.h>17#include <linux/module.h>18#include <linux/pkt_sched.h>19#include <linux/poll.h>20#include <linux/rtnetlink.h>21#include <linux/skbuff.h>22#include <net/x25device.h>23 24struct x25_state {25 x25_hdlc_proto settings;26 bool up;27 spinlock_t up_lock; /* Protects "up" */28 struct sk_buff_head rx_queue;29 struct tasklet_struct rx_tasklet;30};31 32static int x25_ioctl(struct net_device *dev, struct if_settings *ifs);33 34static struct x25_state *state(hdlc_device *hdlc)35{36 return hdlc->state;37}38 39static void x25_rx_queue_kick(struct tasklet_struct *t)40{41 struct x25_state *x25st = from_tasklet(x25st, t, rx_tasklet);42 struct sk_buff *skb = skb_dequeue(&x25st->rx_queue);43 44 while (skb) {45 netif_receive_skb_core(skb);46 skb = skb_dequeue(&x25st->rx_queue);47 }48}49 50/* These functions are callbacks called by LAPB layer */51 52static void x25_connect_disconnect(struct net_device *dev, int reason, int code)53{54 struct x25_state *x25st = state(dev_to_hdlc(dev));55 struct sk_buff *skb;56 unsigned char *ptr;57 58 skb = __dev_alloc_skb(1, GFP_ATOMIC | __GFP_NOMEMALLOC);59 if (!skb)60 return;61 62 ptr = skb_put(skb, 1);63 *ptr = code;64 65 skb->protocol = x25_type_trans(skb, dev);66 67 skb_queue_tail(&x25st->rx_queue, skb);68 tasklet_schedule(&x25st->rx_tasklet);69}70 71static void x25_connected(struct net_device *dev, int reason)72{73 x25_connect_disconnect(dev, reason, X25_IFACE_CONNECT);74}75 76static void x25_disconnected(struct net_device *dev, int reason)77{78 x25_connect_disconnect(dev, reason, X25_IFACE_DISCONNECT);79}80 81static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)82{83 struct x25_state *x25st = state(dev_to_hdlc(dev));84 unsigned char *ptr;85 86 if (skb_cow(skb, 1)) {87 kfree_skb(skb);88 return NET_RX_DROP;89 }90 91 skb_push(skb, 1);92 93 ptr = skb->data;94 *ptr = X25_IFACE_DATA;95 96 skb->protocol = x25_type_trans(skb, dev);97 98 skb_queue_tail(&x25st->rx_queue, skb);99 tasklet_schedule(&x25st->rx_tasklet);100 return NET_RX_SUCCESS;101}102 103static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)104{105 hdlc_device *hdlc = dev_to_hdlc(dev);106 107 skb_reset_network_header(skb);108 skb->protocol = hdlc_type_trans(skb, dev);109 110 if (dev_nit_active(dev))111 dev_queue_xmit_nit(skb, dev);112 113 hdlc->xmit(skb, dev); /* Ignore return value :-( */114}115 116static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)117{118 hdlc_device *hdlc = dev_to_hdlc(dev);119 struct x25_state *x25st = state(hdlc);120 int result;121 122 /* There should be a pseudo header of 1 byte added by upper layers.123 * Check to make sure it is there before reading it.124 */125 if (skb->len < 1) {126 kfree_skb(skb);127 return NETDEV_TX_OK;128 }129 130 spin_lock_bh(&x25st->up_lock);131 if (!x25st->up) {132 spin_unlock_bh(&x25st->up_lock);133 kfree_skb(skb);134 return NETDEV_TX_OK;135 }136 137 switch (skb->data[0]) {138 case X25_IFACE_DATA: /* Data to be transmitted */139 skb_pull(skb, 1);140 result = lapb_data_request(dev, skb);141 if (result != LAPB_OK)142 dev_kfree_skb(skb);143 spin_unlock_bh(&x25st->up_lock);144 return NETDEV_TX_OK;145 146 case X25_IFACE_CONNECT:147 result = lapb_connect_request(dev);148 if (result != LAPB_OK) {149 if (result == LAPB_CONNECTED)150 /* Send connect confirm. msg to level 3 */151 x25_connected(dev, 0);152 else153 netdev_err(dev, "LAPB connect request failed, error code = %i\n",154 result);155 }156 break;157 158 case X25_IFACE_DISCONNECT:159 result = lapb_disconnect_request(dev);160 if (result != LAPB_OK) {161 if (result == LAPB_NOTCONNECTED)162 /* Send disconnect confirm. msg to level 3 */163 x25_disconnected(dev, 0);164 else165 netdev_err(dev, "LAPB disconnect request failed, error code = %i\n",166 result);167 }168 break;169 170 default: /* to be defined */171 break;172 }173 174 spin_unlock_bh(&x25st->up_lock);175 dev_kfree_skb(skb);176 return NETDEV_TX_OK;177}178 179static int x25_open(struct net_device *dev)180{181 static const struct lapb_register_struct cb = {182 .connect_confirmation = x25_connected,183 .connect_indication = x25_connected,184 .disconnect_confirmation = x25_disconnected,185 .disconnect_indication = x25_disconnected,186 .data_indication = x25_data_indication,187 .data_transmit = x25_data_transmit,188 };189 hdlc_device *hdlc = dev_to_hdlc(dev);190 struct x25_state *x25st = state(hdlc);191 struct lapb_parms_struct params;192 int result;193 194 result = lapb_register(dev, &cb);195 if (result != LAPB_OK)196 return -ENOMEM;197 198 result = lapb_getparms(dev, ¶ms);199 if (result != LAPB_OK)200 return -EINVAL;201 202 if (state(hdlc)->settings.dce)203 params.mode = params.mode | LAPB_DCE;204 205 if (state(hdlc)->settings.modulo == 128)206 params.mode = params.mode | LAPB_EXTENDED;207 208 params.window = state(hdlc)->settings.window;209 params.t1 = state(hdlc)->settings.t1;210 params.t2 = state(hdlc)->settings.t2;211 params.n2 = state(hdlc)->settings.n2;212 213 result = lapb_setparms(dev, ¶ms);214 if (result != LAPB_OK)215 return -EINVAL;216 217 spin_lock_bh(&x25st->up_lock);218 x25st->up = true;219 spin_unlock_bh(&x25st->up_lock);220 221 return 0;222}223 224static void x25_close(struct net_device *dev)225{226 hdlc_device *hdlc = dev_to_hdlc(dev);227 struct x25_state *x25st = state(hdlc);228 229 spin_lock_bh(&x25st->up_lock);230 x25st->up = false;231 spin_unlock_bh(&x25st->up_lock);232 233 lapb_unregister(dev);234 tasklet_kill(&x25st->rx_tasklet);235}236 237static int x25_rx(struct sk_buff *skb)238{239 struct net_device *dev = skb->dev;240 hdlc_device *hdlc = dev_to_hdlc(dev);241 struct x25_state *x25st = state(hdlc);242 243 skb = skb_share_check(skb, GFP_ATOMIC);244 if (!skb) {245 dev->stats.rx_dropped++;246 return NET_RX_DROP;247 }248 249 spin_lock_bh(&x25st->up_lock);250 if (!x25st->up) {251 spin_unlock_bh(&x25st->up_lock);252 kfree_skb(skb);253 dev->stats.rx_dropped++;254 return NET_RX_DROP;255 }256 257 if (lapb_data_received(dev, skb) == LAPB_OK) {258 spin_unlock_bh(&x25st->up_lock);259 return NET_RX_SUCCESS;260 }261 262 spin_unlock_bh(&x25st->up_lock);263 dev->stats.rx_errors++;264 dev_kfree_skb_any(skb);265 return NET_RX_DROP;266}267 268static struct hdlc_proto proto = {269 .open = x25_open,270 .close = x25_close,271 .ioctl = x25_ioctl,272 .netif_rx = x25_rx,273 .xmit = x25_xmit,274 .module = THIS_MODULE,275};276 277static int x25_ioctl(struct net_device *dev, struct if_settings *ifs)278{279 x25_hdlc_proto __user *x25_s = ifs->ifs_ifsu.x25;280 const size_t size = sizeof(x25_hdlc_proto);281 hdlc_device *hdlc = dev_to_hdlc(dev);282 x25_hdlc_proto new_settings;283 int result;284 285 switch (ifs->type) {286 case IF_GET_PROTO:287 if (dev_to_hdlc(dev)->proto != &proto)288 return -EINVAL;289 ifs->type = IF_PROTO_X25;290 if (ifs->size < size) {291 ifs->size = size; /* data size wanted */292 return -ENOBUFS;293 }294 if (copy_to_user(x25_s, &state(hdlc)->settings, size))295 return -EFAULT;296 return 0;297 298 case IF_PROTO_X25:299 if (!capable(CAP_NET_ADMIN))300 return -EPERM;301 302 if (dev->flags & IFF_UP)303 return -EBUSY;304 305 /* backward compatibility */306 if (ifs->size == 0) {307 new_settings.dce = 0;308 new_settings.modulo = 8;309 new_settings.window = 7;310 new_settings.t1 = 3;311 new_settings.t2 = 1;312 new_settings.n2 = 10;313 } else {314 if (copy_from_user(&new_settings, x25_s, size))315 return -EFAULT;316 317 if ((new_settings.dce != 0 &&318 new_settings.dce != 1) ||319 (new_settings.modulo != 8 &&320 new_settings.modulo != 128) ||321 new_settings.window < 1 ||322 (new_settings.modulo == 8 &&323 new_settings.window > 7) ||324 (new_settings.modulo == 128 &&325 new_settings.window > 127) ||326 new_settings.t1 < 1 ||327 new_settings.t1 > 255 ||328 new_settings.t2 < 1 ||329 new_settings.t2 > 255 ||330 new_settings.n2 < 1 ||331 new_settings.n2 > 255)332 return -EINVAL;333 }334 335 result = hdlc->attach(dev, ENCODING_NRZ,336 PARITY_CRC16_PR1_CCITT);337 if (result)338 return result;339 340 result = attach_hdlc_protocol(dev, &proto,341 sizeof(struct x25_state));342 if (result)343 return result;344 345 memcpy(&state(hdlc)->settings, &new_settings, size);346 state(hdlc)->up = false;347 spin_lock_init(&state(hdlc)->up_lock);348 skb_queue_head_init(&state(hdlc)->rx_queue);349 tasklet_setup(&state(hdlc)->rx_tasklet, x25_rx_queue_kick);350 351 /* There's no header_ops so hard_header_len should be 0. */352 dev->hard_header_len = 0;353 /* When transmitting data:354 * first we'll remove a pseudo header of 1 byte,355 * then we'll prepend an LAPB header of at most 3 bytes.356 */357 dev->needed_headroom = 3 - 1;358 359 dev->type = ARPHRD_X25;360 call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);361 netif_dormant_off(dev);362 return 0;363 }364 365 return -EINVAL;366}367 368static int __init hdlc_x25_init(void)369{370 register_hdlc_protocol(&proto);371 return 0;372}373 374static void __exit hdlc_x25_exit(void)375{376 unregister_hdlc_protocol(&proto);377}378 379module_init(hdlc_x25_init);380module_exit(hdlc_x25_exit);381 382MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");383MODULE_DESCRIPTION("X.25 protocol support for generic HDLC");384MODULE_LICENSE("GPL v2");385