xref: /openbmc/linux/drivers/net/wan/hdlc_ppp.c (revision ab611487d8ada506e511d2b8f22fb8e7be9939b9)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Generic HDLC support routines for Linux
31da177e4SLinus Torvalds  * Point-to-point protocol support
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify it
81da177e4SLinus Torvalds  * under the terms of version 2 of the GNU General Public License
91da177e4SLinus Torvalds  * as published by the Free Software Foundation.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/slab.h>
151da177e4SLinus Torvalds #include <linux/poll.h>
161da177e4SLinus Torvalds #include <linux/errno.h>
171da177e4SLinus Torvalds #include <linux/if_arp.h>
181da177e4SLinus Torvalds #include <linux/init.h>
191da177e4SLinus Torvalds #include <linux/skbuff.h>
201da177e4SLinus Torvalds #include <linux/pkt_sched.h>
211da177e4SLinus Torvalds #include <linux/inetdevice.h>
221da177e4SLinus Torvalds #include <linux/lapb.h>
231da177e4SLinus Torvalds #include <linux/rtnetlink.h>
241da177e4SLinus Torvalds #include <linux/hdlc.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds static int ppp_open(struct net_device *dev)
281da177e4SLinus Torvalds {
291da177e4SLinus Torvalds 	hdlc_device *hdlc = dev_to_hdlc(dev);
301da177e4SLinus Torvalds 	void *old_ioctl;
311da177e4SLinus Torvalds 	int result;
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds 	dev->priv = &hdlc->state.ppp.syncppp_ptr;
341da177e4SLinus Torvalds 	hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
351da177e4SLinus Torvalds 	hdlc->state.ppp.pppdev.dev = dev;
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 	old_ioctl = dev->do_ioctl;
381da177e4SLinus Torvalds 	hdlc->state.ppp.old_change_mtu = dev->change_mtu;
391da177e4SLinus Torvalds 	sppp_attach(&hdlc->state.ppp.pppdev);
401da177e4SLinus Torvalds 	/* sppp_attach nukes them. We don't need syncppp's ioctl */
411da177e4SLinus Torvalds 	dev->do_ioctl = old_ioctl;
421da177e4SLinus Torvalds 	hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
431da177e4SLinus Torvalds 	dev->type = ARPHRD_PPP;
441da177e4SLinus Torvalds 	result = sppp_open(dev);
451da177e4SLinus Torvalds 	if (result) {
461da177e4SLinus Torvalds 		sppp_detach(dev);
471da177e4SLinus Torvalds 		return result;
481da177e4SLinus Torvalds 	}
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	return 0;
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds static void ppp_close(struct net_device *dev)
561da177e4SLinus Torvalds {
571da177e4SLinus Torvalds 	hdlc_device *hdlc = dev_to_hdlc(dev);
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	sppp_close(dev);
601da177e4SLinus Torvalds 	sppp_detach(dev);
611da177e4SLinus Torvalds 	dev->rebuild_header = NULL;
621da177e4SLinus Torvalds 	dev->change_mtu = hdlc->state.ppp.old_change_mtu;
631da177e4SLinus Torvalds 	dev->mtu = HDLC_MAX_MTU;
641da177e4SLinus Torvalds 	dev->hard_header_len = 16;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 
69*ab611487SAlexey Dobriyan static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds 	return __constant_htons(ETH_P_WAN_PPP);
721da177e4SLinus Torvalds }
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
771da177e4SLinus Torvalds {
781da177e4SLinus Torvalds 	hdlc_device *hdlc = dev_to_hdlc(dev);
791da177e4SLinus Torvalds 	int result;
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds 	switch (ifr->ifr_settings.type) {
821da177e4SLinus Torvalds 	case IF_GET_PROTO:
831da177e4SLinus Torvalds 		ifr->ifr_settings.type = IF_PROTO_PPP;
841da177e4SLinus Torvalds 		return 0; /* return protocol only, no settable parameters */
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	case IF_PROTO_PPP:
871da177e4SLinus Torvalds 		if(!capable(CAP_NET_ADMIN))
881da177e4SLinus Torvalds 			return -EPERM;
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 		if(dev->flags & IFF_UP)
911da177e4SLinus Torvalds 			return -EBUSY;
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 		/* no settable parameters */
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds 		result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
961da177e4SLinus Torvalds 		if (result)
971da177e4SLinus Torvalds 			return result;
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 		hdlc_proto_detach(hdlc);
1001da177e4SLinus Torvalds 		memset(&hdlc->proto, 0, sizeof(hdlc->proto));
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 		hdlc->proto.open = ppp_open;
1031da177e4SLinus Torvalds 		hdlc->proto.close = ppp_close;
1041da177e4SLinus Torvalds 		hdlc->proto.type_trans = ppp_type_trans;
1051da177e4SLinus Torvalds 		hdlc->proto.id = IF_PROTO_PPP;
1061da177e4SLinus Torvalds 		dev->hard_start_xmit = hdlc->xmit;
1071da177e4SLinus Torvalds 		dev->hard_header = NULL;
1081da177e4SLinus Torvalds 		dev->type = ARPHRD_PPP;
1091da177e4SLinus Torvalds 		dev->addr_len = 0;
1101da177e4SLinus Torvalds 		return 0;
1111da177e4SLinus Torvalds 	}
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	return -EINVAL;
1141da177e4SLinus Torvalds }
115