14
14
#include <linux/types.h>
15
15
#include <linux/termios.h>
16
16
#include <linux/wwan.h>
17
+ #include <net/rtnetlink.h>
18
+ #include <uapi/linux/wwan.h>
17
19
18
20
/* Maximum number of minors in use */
19
21
#define WWAN_MAX_MINORS (1 << MINORBITS)
@@ -35,10 +37,16 @@ static int wwan_major;
35
37
*
36
38
* @id: WWAN device unique ID.
37
39
* @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
38
43
*/
39
44
struct wwan_device {
40
45
unsigned int id ;
41
46
struct device dev ;
47
+ atomic_t port_id ;
48
+ const struct wwan_ops * ops ;
49
+ void * ops_ctxt ;
42
50
};
43
51
44
52
/**
@@ -102,7 +110,8 @@ static const struct device_type wwan_dev_type = {
102
110
103
111
static int wwan_dev_parent_match (struct device * dev , const void * parent )
104
112
{
105
- return (dev -> type == & wwan_dev_type && dev -> parent == parent );
113
+ return (dev -> type == & wwan_dev_type &&
114
+ (dev -> parent == parent || dev == parent ));
106
115
}
107
116
108
117
static 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)
116
125
return to_wwan_dev (dev );
117
126
}
118
127
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
+
119
145
/* This function allocates and registers a new WWAN device OR if a WWAN device
120
146
* already exist for the given parent, it gets a reference and return it.
121
147
* 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)
180
206
/* WWAN device is created and registered (get+add) along with its first
181
207
* child port, and subsequent port registrations only grab a reference
182
208
* (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.
184
211
*/
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
+
186
217
if (!ret )
187
218
device_unregister (& wwandev -> dev );
188
219
else
@@ -750,26 +781,226 @@ static const struct file_operations wwan_port_fops = {
750
781
.llseek = noop_llseek ,
751
782
};
752
783
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
+
753
969
static int __init wwan_init (void )
754
970
{
971
+ int err ;
972
+
973
+ err = rtnl_link_register (& wwan_rtnl_link_ops );
974
+ if (err )
975
+ return err ;
976
+
755
977
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
+ }
758
982
759
983
/* chrdev used for wwan ports */
760
984
wwan_major = __register_chrdev (0 , 0 , WWAN_MAX_MINORS , "wwan_port" ,
761
985
& wwan_port_fops );
762
986
if (wwan_major < 0 ) {
763
- class_destroy ( wwan_class ) ;
764
- return wwan_major ;
987
+ err = wwan_major ;
988
+ goto destroy ;
765
989
}
766
990
767
991
return 0 ;
992
+
993
+ destroy :
994
+ class_destroy (wwan_class );
995
+ unregister :
996
+ rtnl_link_unregister (& wwan_rtnl_link_ops );
997
+ return err ;
768
998
}
769
999
770
1000
static void __exit wwan_exit (void )
771
1001
{
772
1002
__unregister_chrdev (wwan_major , 0 , WWAN_MAX_MINORS , "wwan_port" );
1003
+ rtnl_link_unregister (& wwan_rtnl_link_ops );
773
1004
class_destroy (wwan_class );
774
1005
}
775
1006
0 commit comments