1414#include <linux/types.h>
1515#include <linux/termios.h>
1616#include <linux/wwan.h>
17+ #include <net/rtnetlink.h>
18+ #include <uapi/linux/wwan.h>
1719
1820/* Maximum number of minors in use */
1921#define WWAN_MAX_MINORS (1 << MINORBITS)
@@ -35,10 +37,16 @@ static int wwan_major;
3537 *
3638 * @id: WWAN device unique ID.
3739 * @dev: Underlying device.
40+ * @port_id: Current available port ID to pick.
41+ * @ops: wwan device ops
42+ * @ops_ctxt: context to pass to ops
3843 */
3944struct wwan_device {
4045 unsigned int id ;
4146 struct device dev ;
47+ atomic_t port_id ;
48+ const struct wwan_ops * ops ;
49+ void * ops_ctxt ;
4250};
4351
4452/**
@@ -102,7 +110,8 @@ static const struct device_type wwan_dev_type = {
102110
103111static int wwan_dev_parent_match (struct device * dev , const void * parent )
104112{
105- return (dev -> type == & wwan_dev_type && dev -> parent == parent );
113+ return (dev -> type == & wwan_dev_type &&
114+ (dev -> parent == parent || dev == parent ));
106115}
107116
108117static struct wwan_device * wwan_dev_get_by_parent (struct device * parent )
@@ -116,6 +125,23 @@ static struct wwan_device *wwan_dev_get_by_parent(struct device *parent)
116125 return to_wwan_dev (dev );
117126}
118127
128+ static int wwan_dev_name_match (struct device * dev , const void * name )
129+ {
130+ return dev -> type == & wwan_dev_type &&
131+ strcmp (dev_name (dev ), name ) == 0 ;
132+ }
133+
134+ static struct wwan_device * wwan_dev_get_by_name (const char * name )
135+ {
136+ struct device * dev ;
137+
138+ dev = class_find_device (wwan_class , NULL , name , wwan_dev_name_match );
139+ if (!dev )
140+ return ERR_PTR (- ENODEV );
141+
142+ return to_wwan_dev (dev );
143+ }
144+
119145/* This function allocates and registers a new WWAN device OR if a WWAN device
120146 * already exist for the given parent, it gets a reference and return it.
121147 * This function is not exported (for now), it is called indirectly via
@@ -180,9 +206,14 @@ static void wwan_remove_dev(struct wwan_device *wwandev)
180206 /* WWAN device is created and registered (get+add) along with its first
181207 * child port, and subsequent port registrations only grab a reference
182208 * (get). The WWAN device must then be unregistered (del+put) along with
183- * its latest port, and reference simply dropped (put) otherwise.
209+ * its last port, and reference simply dropped (put) otherwise. In the
210+ * same fashion, we must not unregister it when the ops are still there.
184211 */
185- ret = device_for_each_child (& wwandev -> dev , NULL , is_wwan_child );
212+ if (wwandev -> ops )
213+ ret = 1 ;
214+ else
215+ ret = device_for_each_child (& wwandev -> dev , NULL , is_wwan_child );
216+
186217 if (!ret )
187218 device_unregister (& wwandev -> dev );
188219 else
@@ -750,26 +781,226 @@ static const struct file_operations wwan_port_fops = {
750781 .llseek = noop_llseek ,
751782};
752783
784+ /**
785+ * wwan_register_ops - register WWAN device ops
786+ * @parent: Device to use as parent and shared by all WWAN ports and
787+ * created netdevs
788+ * @ops: operations to register
789+ * @ctxt: context to pass to operations
790+ *
791+ * Returns: 0 on success, a negative error code on failure
792+ */
793+ int wwan_register_ops (struct device * parent , const struct wwan_ops * ops ,
794+ void * ctxt )
795+ {
796+ struct wwan_device * wwandev ;
797+
798+ if (WARN_ON (!parent || !ops ))
799+ return - EINVAL ;
800+
801+ wwandev = wwan_create_dev (parent );
802+ if (!wwandev )
803+ return - ENOMEM ;
804+
805+ if (WARN_ON (wwandev -> ops )) {
806+ wwan_remove_dev (wwandev );
807+ return - EBUSY ;
808+ }
809+
810+ if (!try_module_get (ops -> owner )) {
811+ wwan_remove_dev (wwandev );
812+ return - ENODEV ;
813+ }
814+
815+ wwandev -> ops = ops ;
816+ wwandev -> ops_ctxt = ctxt ;
817+
818+ return 0 ;
819+ }
820+ EXPORT_SYMBOL_GPL (wwan_register_ops );
821+
822+ /**
823+ * wwan_unregister_ops - remove WWAN device ops
824+ * @parent: Device to use as parent and shared by all WWAN ports and
825+ * created netdevs
826+ */
827+ void wwan_unregister_ops (struct device * parent )
828+ {
829+ struct wwan_device * wwandev = wwan_dev_get_by_parent (parent );
830+ bool has_ops ;
831+
832+ if (WARN_ON (IS_ERR (wwandev )))
833+ return ;
834+
835+ has_ops = wwandev -> ops ;
836+
837+ /* put the reference obtained by wwan_dev_get_by_parent(),
838+ * we should still have one (that the owner is giving back
839+ * now) due to the ops being assigned, check that below
840+ * and return if not.
841+ */
842+ put_device (& wwandev -> dev );
843+
844+ if (WARN_ON (!has_ops ))
845+ return ;
846+
847+ module_put (wwandev -> ops -> owner );
848+
849+ wwandev -> ops = NULL ;
850+ wwandev -> ops_ctxt = NULL ;
851+ wwan_remove_dev (wwandev );
852+ }
853+ EXPORT_SYMBOL_GPL (wwan_unregister_ops );
854+
855+ static int wwan_rtnl_validate (struct nlattr * tb [], struct nlattr * data [],
856+ struct netlink_ext_ack * extack )
857+ {
858+ if (!data )
859+ return - EINVAL ;
860+
861+ if (!tb [IFLA_PARENT_DEV_NAME ])
862+ return - EINVAL ;
863+
864+ if (!data [IFLA_WWAN_LINK_ID ])
865+ return - EINVAL ;
866+
867+ return 0 ;
868+ }
869+
870+ static struct device_type wwan_type = { .name = "wwan" };
871+
872+ static struct net_device * wwan_rtnl_alloc (struct nlattr * tb [],
873+ const char * ifname ,
874+ unsigned char name_assign_type ,
875+ unsigned int num_tx_queues ,
876+ unsigned int num_rx_queues )
877+ {
878+ const char * devname = nla_data (tb [IFLA_PARENT_DEV_NAME ]);
879+ struct wwan_device * wwandev = wwan_dev_get_by_name (devname );
880+ struct net_device * dev ;
881+
882+ if (IS_ERR (wwandev ))
883+ return ERR_CAST (wwandev );
884+
885+ /* only supported if ops were registered (not just ports) */
886+ if (!wwandev -> ops ) {
887+ dev = ERR_PTR (- EOPNOTSUPP );
888+ goto out ;
889+ }
890+
891+ dev = alloc_netdev_mqs (wwandev -> ops -> priv_size , ifname , name_assign_type ,
892+ wwandev -> ops -> setup , num_tx_queues , num_rx_queues );
893+
894+ if (dev ) {
895+ SET_NETDEV_DEV (dev , & wwandev -> dev );
896+ SET_NETDEV_DEVTYPE (dev , & wwan_type );
897+ }
898+
899+ out :
900+ /* release the reference */
901+ put_device (& wwandev -> dev );
902+ return dev ;
903+ }
904+
905+ static int wwan_rtnl_newlink (struct net * src_net , struct net_device * dev ,
906+ struct nlattr * tb [], struct nlattr * data [],
907+ struct netlink_ext_ack * extack )
908+ {
909+ struct wwan_device * wwandev = wwan_dev_get_by_parent (dev -> dev .parent );
910+ u32 link_id = nla_get_u32 (data [IFLA_WWAN_LINK_ID ]);
911+ int ret ;
912+
913+ if (IS_ERR (wwandev ))
914+ return PTR_ERR (wwandev );
915+
916+ /* shouldn't have a netdev (left) with us as parent so WARN */
917+ if (WARN_ON (!wwandev -> ops )) {
918+ ret = - EOPNOTSUPP ;
919+ goto out ;
920+ }
921+
922+ if (wwandev -> ops -> newlink )
923+ ret = wwandev -> ops -> newlink (wwandev -> ops_ctxt , dev ,
924+ link_id , extack );
925+ else
926+ ret = register_netdevice (dev );
927+
928+ out :
929+ /* release the reference */
930+ put_device (& wwandev -> dev );
931+ return ret ;
932+ }
933+
934+ static void wwan_rtnl_dellink (struct net_device * dev , struct list_head * head )
935+ {
936+ struct wwan_device * wwandev = wwan_dev_get_by_parent (dev -> dev .parent );
937+
938+ if (IS_ERR (wwandev ))
939+ return ;
940+
941+ /* shouldn't have a netdev (left) with us as parent so WARN */
942+ if (WARN_ON (!wwandev -> ops ))
943+ goto out ;
944+
945+ if (wwandev -> ops -> dellink )
946+ wwandev -> ops -> dellink (wwandev -> ops_ctxt , dev , head );
947+ else
948+ unregister_netdevice (dev );
949+
950+ out :
951+ /* release the reference */
952+ put_device (& wwandev -> dev );
953+ }
954+
955+ static const struct nla_policy wwan_rtnl_policy [IFLA_WWAN_MAX + 1 ] = {
956+ [IFLA_WWAN_LINK_ID ] = { .type = NLA_U32 },
957+ };
958+
959+ static struct rtnl_link_ops wwan_rtnl_link_ops __read_mostly = {
960+ .kind = "wwan" ,
961+ .maxtype = __IFLA_WWAN_MAX ,
962+ .alloc = wwan_rtnl_alloc ,
963+ .validate = wwan_rtnl_validate ,
964+ .newlink = wwan_rtnl_newlink ,
965+ .dellink = wwan_rtnl_dellink ,
966+ .policy = wwan_rtnl_policy ,
967+ };
968+
753969static int __init wwan_init (void )
754970{
971+ int err ;
972+
973+ err = rtnl_link_register (& wwan_rtnl_link_ops );
974+ if (err )
975+ return err ;
976+
755977 wwan_class = class_create (THIS_MODULE , "wwan" );
756- if (IS_ERR (wwan_class ))
757- return PTR_ERR (wwan_class );
978+ if (IS_ERR (wwan_class )) {
979+ err = PTR_ERR (wwan_class );
980+ goto unregister ;
981+ }
758982
759983 /* chrdev used for wwan ports */
760984 wwan_major = __register_chrdev (0 , 0 , WWAN_MAX_MINORS , "wwan_port" ,
761985 & wwan_port_fops );
762986 if (wwan_major < 0 ) {
763- class_destroy ( wwan_class ) ;
764- return wwan_major ;
987+ err = wwan_major ;
988+ goto destroy ;
765989 }
766990
767991 return 0 ;
992+
993+ destroy :
994+ class_destroy (wwan_class );
995+ unregister :
996+ rtnl_link_unregister (& wwan_rtnl_link_ops );
997+ return err ;
768998}
769999
7701000static void __exit wwan_exit (void )
7711001{
7721002 __unregister_chrdev (wwan_major , 0 , WWAN_MAX_MINORS , "wwan_port" );
1003+ rtnl_link_unregister (& wwan_rtnl_link_ops );
7731004 class_destroy (wwan_class );
7741005}
7751006
0 commit comments