#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)
 
 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,
                .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, ¶ms);
+       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, ¶ms);
+       if (result != LAPB_OK)
+               return result;
+
        return 0;
 }
 
 
 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) {
                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))
                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);