wan/hdlc_x25: make lapb params configurable
authorMartin Schiller <ms@dev.tdt.de>
Tue, 21 Jan 2020 06:00:33 +0000 (07:00 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 21 Jan 2020 10:41:36 +0000 (11:41 +0100)
This enables you to configure mode (DTE/DCE), Modulo, Window, T1, T2, N2 via
sethdlc (which needs to be patched as well).

Signed-off-by: Martin Schiller <ms@dev.tdt.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/wan/hdlc_x25.c
include/uapi/linux/hdlc/ioctl.h
include/uapi/linux/if.h

index 5643675ff7241873fac78da7f54e6bb9809279c8..688233c2e1ea0e2c12664330705d9c894ccd617a 100644 (file)
 #include <linux/skbuff.h>
 #include <net/x25device.h>
 
+struct x25_state {
+       x25_hdlc_proto settings;
+};
+
 static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
 
+static struct x25_state *state(hdlc_device *hdlc)
+{
+       return hdlc->state;
+}
+
 /* These functions are callbacks called by LAPB layer */
 
 static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
@@ -131,7 +140,6 @@ static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static int x25_open(struct net_device *dev)
 {
-       int result;
        static const struct lapb_register_struct cb = {
                .connect_confirmation = x25_connected,
                .connect_indication = x25_connected,
@@ -140,10 +148,33 @@ static int x25_open(struct net_device *dev)
                .data_indication = x25_data_indication,
                .data_transmit = x25_data_transmit,
        };
+       hdlc_device *hdlc = dev_to_hdlc(dev);
+       struct lapb_parms_struct params;
+       int result;
 
        result = lapb_register(dev, &cb);
        if (result != LAPB_OK)
                return result;
+
+       result = lapb_getparms(dev, &params);
+       if (result != LAPB_OK)
+               return result;
+
+       if (state(hdlc)->settings.dce)
+               params.mode = params.mode | LAPB_DCE;
+
+       if (state(hdlc)->settings.modulo == 128)
+               params.mode = params.mode | LAPB_EXTENDED;
+
+       params.window = state(hdlc)->settings.window;
+       params.t1 = state(hdlc)->settings.t1;
+       params.t2 = state(hdlc)->settings.t2;
+       params.n2 = state(hdlc)->settings.n2;
+
+       result = lapb_setparms(dev, &params);
+       if (result != LAPB_OK)
+               return result;
+
        return 0;
 }
 
@@ -186,7 +217,10 @@ static struct hdlc_proto proto = {
 
 static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
+       x25_hdlc_proto __user *x25_s = ifr->ifr_settings.ifs_ifsu.x25;
+       const size_t size = sizeof(x25_hdlc_proto);
        hdlc_device *hdlc = dev_to_hdlc(dev);
+       x25_hdlc_proto new_settings;
        int result;
 
        switch (ifr->ifr_settings.type) {
@@ -194,7 +228,13 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (dev_to_hdlc(dev)->proto != &proto)
                        return -EINVAL;
                ifr->ifr_settings.type = IF_PROTO_X25;
-               return 0; /* return protocol only, no settable parameters */
+               if (ifr->ifr_settings.size < size) {
+                       ifr->ifr_settings.size = size; /* data size wanted */
+                       return -ENOBUFS;
+               }
+               if (copy_to_user(x25_s, &state(hdlc)->settings, size))
+                       return -EFAULT;
+               return 0;
 
        case IF_PROTO_X25:
                if (!capable(CAP_NET_ADMIN))
@@ -203,12 +243,46 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (dev->flags & IFF_UP)
                        return -EBUSY;
 
+               /* backward compatibility */
+               if (ifr->ifr_settings.size = 0) {
+                       new_settings.dce = 0;
+                       new_settings.modulo = 8;
+                       new_settings.window = 7;
+                       new_settings.t1 = 3;
+                       new_settings.t2 = 1;
+                       new_settings.n2 = 10;
+               }
+               else {
+                       if (copy_from_user(&new_settings, x25_s, size))
+                               return -EFAULT;
+
+                       if ((new_settings.dce != 0 &&
+                       new_settings.dce != 1) ||
+                       (new_settings.modulo != 8 &&
+                       new_settings.modulo != 128) ||
+                       new_settings.window < 1 ||
+                       (new_settings.modulo == 8 &&
+                       new_settings.window > 7) ||
+                       (new_settings.modulo == 128 &&
+                       new_settings.window > 127) ||
+                       new_settings.t1 < 1 ||
+                       new_settings.t1 > 255 ||
+                       new_settings.t2 < 1 ||
+                       new_settings.t2 > 255 ||
+                       new_settings.n2 < 1 ||
+                       new_settings.n2 > 255)
+                               return -EINVAL;
+               }
+
                result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
                if (result)
                        return result;
 
-               if ((result = attach_hdlc_protocol(dev, &proto, 0)))
+               if ((result = attach_hdlc_protocol(dev, &proto,
+                                                  sizeof(struct x25_state))))
                        return result;
+
+               memcpy(&state(hdlc)->settings, &new_settings, size);
                dev->type = ARPHRD_X25;
                call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);
                netif_dormant_off(dev);
index 0fe4238e824624d22b847cca023bec3fbb709324..b06341acab5ec9815a5b24670a664301a0357b6f 100644 (file)
@@ -79,6 +79,15 @@ typedef struct {
     unsigned int timeout;
 } cisco_proto;
 
+typedef struct {
+       unsigned short dce; /* 1 for DCE (network side) operation */
+       unsigned int modulo; /* modulo (8 = basic / 128 = extended) */
+       unsigned int window; /* frame window size */
+       unsigned int t1; /* timeout t1 */
+       unsigned int t2; /* timeout t2 */
+       unsigned int n2; /* frame retry counter */
+} x25_hdlc_proto;
+
 /* PPP doesn't need any info now - supply length = 0 to ioctl */
 
 #endif /* __ASSEMBLY__ */
index 4bf33344aab198fe3564a37def851f58cf226d34..be714cd8c826d72a535f7b4caa48b1bf5666fdb2 100644 (file)
@@ -213,6 +213,7 @@ struct if_settings {
                fr_proto                __user *fr;
                fr_proto_pvc            __user *fr_pvc;
                fr_proto_pvc_info       __user *fr_pvc_info;
+               x25_hdlc_proto          __user *x25;
 
                /* interface settings */
                sync_serial_settings    __user *sync;