162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Generic HDLC support routines for Linux
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1999 - 2008 Krzysztof Halasa <khc@pm.waw.pl>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Currently supported:
862306a36Sopenharmony_ci *	* raw IP-in-HDLC
962306a36Sopenharmony_ci *	* Cisco HDLC
1062306a36Sopenharmony_ci *	* Frame Relay with ANSI or CCITT LMI (both user and network side)
1162306a36Sopenharmony_ci *	* PPP
1262306a36Sopenharmony_ci *	* X.25
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Use sethdlc utility to set line parameters, protocol and PVCs
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * How does it work:
1762306a36Sopenharmony_ci * - proto->open(), close(), start(), stop() calls are serialized.
1862306a36Sopenharmony_ci *   The order is: open, [ start, stop ... ] close ...
1962306a36Sopenharmony_ci * - proto->start() and stop() are called with spin_lock_irq held.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <linux/errno.h>
2562306a36Sopenharmony_ci#include <linux/hdlc.h>
2662306a36Sopenharmony_ci#include <linux/if_arp.h>
2762306a36Sopenharmony_ci#include <linux/inetdevice.h>
2862306a36Sopenharmony_ci#include <linux/init.h>
2962306a36Sopenharmony_ci#include <linux/kernel.h>
3062306a36Sopenharmony_ci#include <linux/module.h>
3162306a36Sopenharmony_ci#include <linux/notifier.h>
3262306a36Sopenharmony_ci#include <linux/pkt_sched.h>
3362306a36Sopenharmony_ci#include <linux/poll.h>
3462306a36Sopenharmony_ci#include <linux/rtnetlink.h>
3562306a36Sopenharmony_ci#include <linux/skbuff.h>
3662306a36Sopenharmony_ci#include <linux/slab.h>
3762306a36Sopenharmony_ci#include <net/net_namespace.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const char *version = "HDLC support module revision 1.22";
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#undef DEBUG_LINK
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic struct hdlc_proto *first_proto;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
4662306a36Sopenharmony_ci		    struct packet_type *p, struct net_device *orig_dev)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct hdlc_device *hdlc;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/* First make sure "dev" is an HDLC device */
5162306a36Sopenharmony_ci	if (!(dev->priv_flags & IFF_WAN_HDLC)) {
5262306a36Sopenharmony_ci		kfree_skb(skb);
5362306a36Sopenharmony_ci		return NET_RX_SUCCESS;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	hdlc = dev_to_hdlc(dev);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (!net_eq(dev_net(dev), &init_net)) {
5962306a36Sopenharmony_ci		kfree_skb(skb);
6062306a36Sopenharmony_ci		return 0;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	BUG_ON(!hdlc->proto->netif_rx);
6462306a36Sopenharmony_ci	return hdlc->proto->netif_rx(skb);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cinetdev_tx_t hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	hdlc_device *hdlc = dev_to_hdlc(dev);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (hdlc->proto->xmit)
7262306a36Sopenharmony_ci		return hdlc->proto->xmit(skb, dev);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return hdlc->xmit(skb, dev); /* call hardware driver directly */
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ciEXPORT_SYMBOL(hdlc_start_xmit);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic inline void hdlc_proto_start(struct net_device *dev)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	hdlc_device *hdlc = dev_to_hdlc(dev);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (hdlc->proto->start)
8362306a36Sopenharmony_ci		hdlc->proto->start(dev);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic inline void hdlc_proto_stop(struct net_device *dev)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	hdlc_device *hdlc = dev_to_hdlc(dev);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (hdlc->proto->stop)
9162306a36Sopenharmony_ci		hdlc->proto->stop(dev);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int hdlc_device_event(struct notifier_block *this, unsigned long event,
9562306a36Sopenharmony_ci			     void *ptr)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
9862306a36Sopenharmony_ci	hdlc_device *hdlc;
9962306a36Sopenharmony_ci	unsigned long flags;
10062306a36Sopenharmony_ci	int on;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (!net_eq(dev_net(dev), &init_net))
10362306a36Sopenharmony_ci		return NOTIFY_DONE;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (!(dev->priv_flags & IFF_WAN_HDLC))
10662306a36Sopenharmony_ci		return NOTIFY_DONE; /* not an HDLC device */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (event != NETDEV_CHANGE)
10962306a36Sopenharmony_ci		return NOTIFY_DONE; /* Only interested in carrier changes */
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	on = netif_carrier_ok(dev);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#ifdef DEBUG_LINK
11462306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n",
11562306a36Sopenharmony_ci	       dev->name, on);
11662306a36Sopenharmony_ci#endif
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	hdlc = dev_to_hdlc(dev);
11962306a36Sopenharmony_ci	spin_lock_irqsave(&hdlc->state_lock, flags);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (hdlc->carrier == on)
12262306a36Sopenharmony_ci		goto carrier_exit; /* no change in DCD line level */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	hdlc->carrier = on;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (!hdlc->open)
12762306a36Sopenharmony_ci		goto carrier_exit;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (hdlc->carrier) {
13062306a36Sopenharmony_ci		netdev_info(dev, "Carrier detected\n");
13162306a36Sopenharmony_ci		hdlc_proto_start(dev);
13262306a36Sopenharmony_ci	} else {
13362306a36Sopenharmony_ci		netdev_info(dev, "Carrier lost\n");
13462306a36Sopenharmony_ci		hdlc_proto_stop(dev);
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cicarrier_exit:
13862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdlc->state_lock, flags);
13962306a36Sopenharmony_ci	return NOTIFY_DONE;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* Must be called by hardware driver when HDLC device is being opened */
14362306a36Sopenharmony_ciint hdlc_open(struct net_device *dev)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	hdlc_device *hdlc = dev_to_hdlc(dev);
14662306a36Sopenharmony_ci#ifdef DEBUG_LINK
14762306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name,
14862306a36Sopenharmony_ci	       hdlc->carrier, hdlc->open);
14962306a36Sopenharmony_ci#endif
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (!hdlc->proto)
15262306a36Sopenharmony_ci		return -ENOSYS;	/* no protocol attached */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (hdlc->proto->open) {
15562306a36Sopenharmony_ci		int result = hdlc->proto->open(dev);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		if (result)
15862306a36Sopenharmony_ci			return result;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	spin_lock_irq(&hdlc->state_lock);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (hdlc->carrier) {
16462306a36Sopenharmony_ci		netdev_info(dev, "Carrier detected\n");
16562306a36Sopenharmony_ci		hdlc_proto_start(dev);
16662306a36Sopenharmony_ci	} else {
16762306a36Sopenharmony_ci		netdev_info(dev, "No carrier\n");
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	hdlc->open = 1;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	spin_unlock_irq(&hdlc->state_lock);
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ciEXPORT_SYMBOL(hdlc_open);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/* Must be called by hardware driver when HDLC device is being closed */
17862306a36Sopenharmony_civoid hdlc_close(struct net_device *dev)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	hdlc_device *hdlc = dev_to_hdlc(dev);
18162306a36Sopenharmony_ci#ifdef DEBUG_LINK
18262306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name,
18362306a36Sopenharmony_ci	       hdlc->carrier, hdlc->open);
18462306a36Sopenharmony_ci#endif
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	spin_lock_irq(&hdlc->state_lock);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	hdlc->open = 0;
18962306a36Sopenharmony_ci	if (hdlc->carrier)
19062306a36Sopenharmony_ci		hdlc_proto_stop(dev);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	spin_unlock_irq(&hdlc->state_lock);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (hdlc->proto->close)
19562306a36Sopenharmony_ci		hdlc->proto->close(dev);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ciEXPORT_SYMBOL(hdlc_close);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciint hdlc_ioctl(struct net_device *dev, struct if_settings *ifs)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct hdlc_proto *proto = first_proto;
20262306a36Sopenharmony_ci	int result;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (dev_to_hdlc(dev)->proto) {
20562306a36Sopenharmony_ci		result = dev_to_hdlc(dev)->proto->ioctl(dev, ifs);
20662306a36Sopenharmony_ci		if (result != -EINVAL)
20762306a36Sopenharmony_ci			return result;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* Not handled by currently attached protocol (if any) */
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	while (proto) {
21362306a36Sopenharmony_ci		result = proto->ioctl(dev, ifs);
21462306a36Sopenharmony_ci		if (result != -EINVAL)
21562306a36Sopenharmony_ci			return result;
21662306a36Sopenharmony_ci		proto = proto->next;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci	return -EINVAL;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ciEXPORT_SYMBOL(hdlc_ioctl);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic const struct header_ops hdlc_null_ops;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic void hdlc_setup_dev(struct net_device *dev)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	/* Re-init all variables changed by HDLC protocol drivers,
22762306a36Sopenharmony_ci	 * including ether_setup() called from hdlc_raw_eth.c.
22862306a36Sopenharmony_ci	 */
22962306a36Sopenharmony_ci	dev->flags		 = IFF_POINTOPOINT | IFF_NOARP;
23062306a36Sopenharmony_ci	dev->priv_flags		 = IFF_WAN_HDLC;
23162306a36Sopenharmony_ci	dev->mtu		 = HDLC_MAX_MTU;
23262306a36Sopenharmony_ci	dev->min_mtu		 = 68;
23362306a36Sopenharmony_ci	dev->max_mtu		 = HDLC_MAX_MTU;
23462306a36Sopenharmony_ci	dev->type		 = ARPHRD_RAWHDLC;
23562306a36Sopenharmony_ci	dev->hard_header_len	 = 0;
23662306a36Sopenharmony_ci	dev->needed_headroom	 = 0;
23762306a36Sopenharmony_ci	dev->addr_len		 = 0;
23862306a36Sopenharmony_ci	dev->header_ops		 = &hdlc_null_ops;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic void hdlc_setup(struct net_device *dev)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	hdlc_device *hdlc = dev_to_hdlc(dev);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	hdlc_setup_dev(dev);
24662306a36Sopenharmony_ci	hdlc->carrier = 1;
24762306a36Sopenharmony_ci	hdlc->open = 0;
24862306a36Sopenharmony_ci	spin_lock_init(&hdlc->state_lock);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistruct net_device *alloc_hdlcdev(void *priv)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct net_device *dev;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d",
25662306a36Sopenharmony_ci			   NET_NAME_UNKNOWN, hdlc_setup);
25762306a36Sopenharmony_ci	if (dev)
25862306a36Sopenharmony_ci		dev_to_hdlc(dev)->priv = priv;
25962306a36Sopenharmony_ci	return dev;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ciEXPORT_SYMBOL(alloc_hdlcdev);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_civoid unregister_hdlc_device(struct net_device *dev)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	rtnl_lock();
26662306a36Sopenharmony_ci	detach_hdlc_protocol(dev);
26762306a36Sopenharmony_ci	unregister_netdevice(dev);
26862306a36Sopenharmony_ci	rtnl_unlock();
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ciEXPORT_SYMBOL(unregister_hdlc_device);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ciint attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
27362306a36Sopenharmony_ci			 size_t size)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	int err;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	err = detach_hdlc_protocol(dev);
27862306a36Sopenharmony_ci	if (err)
27962306a36Sopenharmony_ci		return err;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (!try_module_get(proto->module))
28262306a36Sopenharmony_ci		return -ENOSYS;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (size) {
28562306a36Sopenharmony_ci		dev_to_hdlc(dev)->state = kmalloc(size, GFP_KERNEL);
28662306a36Sopenharmony_ci		if (!dev_to_hdlc(dev)->state) {
28762306a36Sopenharmony_ci			module_put(proto->module);
28862306a36Sopenharmony_ci			return -ENOBUFS;
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci	dev_to_hdlc(dev)->proto = proto;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return 0;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ciEXPORT_SYMBOL(attach_hdlc_protocol);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ciint detach_hdlc_protocol(struct net_device *dev)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	hdlc_device *hdlc = dev_to_hdlc(dev);
30062306a36Sopenharmony_ci	int err;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (hdlc->proto) {
30362306a36Sopenharmony_ci		err = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev);
30462306a36Sopenharmony_ci		err = notifier_to_errno(err);
30562306a36Sopenharmony_ci		if (err) {
30662306a36Sopenharmony_ci			netdev_err(dev, "Refused to change device type\n");
30762306a36Sopenharmony_ci			return err;
30862306a36Sopenharmony_ci		}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		if (hdlc->proto->detach)
31162306a36Sopenharmony_ci			hdlc->proto->detach(dev);
31262306a36Sopenharmony_ci		module_put(hdlc->proto->module);
31362306a36Sopenharmony_ci		hdlc->proto = NULL;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci	kfree(hdlc->state);
31662306a36Sopenharmony_ci	hdlc->state = NULL;
31762306a36Sopenharmony_ci	hdlc_setup_dev(dev);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return 0;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ciEXPORT_SYMBOL(detach_hdlc_protocol);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_civoid register_hdlc_protocol(struct hdlc_proto *proto)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	rtnl_lock();
32662306a36Sopenharmony_ci	proto->next = first_proto;
32762306a36Sopenharmony_ci	first_proto = proto;
32862306a36Sopenharmony_ci	rtnl_unlock();
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ciEXPORT_SYMBOL(register_hdlc_protocol);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_civoid unregister_hdlc_protocol(struct hdlc_proto *proto)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct hdlc_proto **p;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	rtnl_lock();
33762306a36Sopenharmony_ci	p = &first_proto;
33862306a36Sopenharmony_ci	while (*p != proto) {
33962306a36Sopenharmony_ci		BUG_ON(!*p);
34062306a36Sopenharmony_ci		p = &((*p)->next);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci	*p = proto->next;
34362306a36Sopenharmony_ci	rtnl_unlock();
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ciEXPORT_SYMBOL(unregister_hdlc_protocol);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ciMODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
34862306a36Sopenharmony_ciMODULE_DESCRIPTION("HDLC support module");
34962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic struct packet_type hdlc_packet_type __read_mostly = {
35262306a36Sopenharmony_ci	.type = cpu_to_be16(ETH_P_HDLC),
35362306a36Sopenharmony_ci	.func = hdlc_rcv,
35462306a36Sopenharmony_ci};
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic struct notifier_block hdlc_notifier = {
35762306a36Sopenharmony_ci	.notifier_call = hdlc_device_event,
35862306a36Sopenharmony_ci};
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic int __init hdlc_module_init(void)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	int result;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	pr_info("%s\n", version);
36562306a36Sopenharmony_ci	result = register_netdevice_notifier(&hdlc_notifier);
36662306a36Sopenharmony_ci	if (result)
36762306a36Sopenharmony_ci		return result;
36862306a36Sopenharmony_ci	dev_add_pack(&hdlc_packet_type);
36962306a36Sopenharmony_ci	return 0;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void __exit hdlc_module_exit(void)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	dev_remove_pack(&hdlc_packet_type);
37562306a36Sopenharmony_ci	unregister_netdevice_notifier(&hdlc_notifier);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cimodule_init(hdlc_module_init);
37962306a36Sopenharmony_cimodule_exit(hdlc_module_exit);
380