diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/caif | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'net/caif')
-rw-r--r-- | net/caif/Makefile | 10 | ||||
-rw-r--r-- | net/caif/caif_config_util.c | 92 | ||||
-rw-r--r-- | net/caif/caif_dev.c | 394 | ||||
-rw-r--r-- | net/caif/caif_socket.c | 181 | ||||
-rw-r--r-- | net/caif/cfcnfg.c | 570 | ||||
-rw-r--r-- | net/caif/cfctrl.c | 272 | ||||
-rw-r--r-- | net/caif/cfdbgl.c | 18 | ||||
-rw-r--r-- | net/caif/cfdgml.c | 25 | ||||
-rw-r--r-- | net/caif/cffrml.c | 74 | ||||
-rw-r--r-- | net/caif/cfmuxl.c | 205 | ||||
-rw-r--r-- | net/caif/cfpkt_skbuff.c | 243 | ||||
-rw-r--r-- | net/caif/cfrfml.c | 18 | ||||
-rw-r--r-- | net/caif/cfserl.c | 12 | ||||
-rw-r--r-- | net/caif/cfsrvl.c | 57 | ||||
-rw-r--r-- | net/caif/cfutill.c | 21 | ||||
-rw-r--r-- | net/caif/cfveil.c | 24 | ||||
-rw-r--r-- | net/caif/cfvidl.c | 11 | ||||
-rw-r--r-- | net/caif/chnl_net.c | 123 |
18 files changed, 1151 insertions, 1199 deletions
diff --git a/net/caif/Makefile b/net/caif/Makefile index f87481fb0e65..ebcd4e7e6f47 100644 --- a/net/caif/Makefile +++ b/net/caif/Makefile | |||
@@ -1,16 +1,14 @@ | |||
1 | ifeq ($(CONFIG_CAIF_DEBUG),y) | 1 | ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG |
2 | EXTRA_CFLAGS += -DDEBUG | ||
3 | endif | ||
4 | 2 | ||
5 | caif-objs := caif_dev.o \ | 3 | caif-y := caif_dev.o \ |
6 | cfcnfg.o cfmuxl.o cfctrl.o \ | 4 | cfcnfg.o cfmuxl.o cfctrl.o \ |
7 | cffrml.o cfveil.o cfdbgl.o\ | 5 | cffrml.o cfveil.o cfdbgl.o\ |
8 | cfserl.o cfdgml.o \ | 6 | cfserl.o cfdgml.o \ |
9 | cfrfml.o cfvidl.o cfutill.o \ | 7 | cfrfml.o cfvidl.o cfutill.o \ |
10 | cfsrvl.o cfpkt_skbuff.o caif_config_util.o | 8 | cfsrvl.o cfpkt_skbuff.o |
11 | 9 | ||
12 | obj-$(CONFIG_CAIF) += caif.o | 10 | obj-$(CONFIG_CAIF) += caif.o |
13 | obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o | 11 | obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o |
14 | obj-$(CONFIG_CAIF) += caif_socket.o | 12 | obj-$(CONFIG_CAIF) += caif_socket.o |
15 | 13 | ||
16 | export-objs := caif.o | 14 | export-y := caif.o |
diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c deleted file mode 100644 index 76ae68303d3a..000000000000 --- a/net/caif/caif_config_util.c +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson AB 2010 | ||
3 | * Author: Sjur Brendeland sjur.brandeland@stericsson.com | ||
4 | * License terms: GNU General Public License (GPL) version 2 | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/spinlock.h> | ||
9 | #include <net/caif/cfctrl.h> | ||
10 | #include <net/caif/cfcnfg.h> | ||
11 | #include <net/caif/caif_dev.h> | ||
12 | |||
13 | int connect_req_to_link_param(struct cfcnfg *cnfg, | ||
14 | struct caif_connect_request *s, | ||
15 | struct cfctrl_link_param *l) | ||
16 | { | ||
17 | struct dev_info *dev_info; | ||
18 | enum cfcnfg_phy_preference pref; | ||
19 | memset(l, 0, sizeof(*l)); | ||
20 | l->priority = s->priority; | ||
21 | |||
22 | if (s->link_name[0] != '\0') | ||
23 | l->phyid = cfcnfg_get_named(cnfg, s->link_name); | ||
24 | else { | ||
25 | switch (s->link_selector) { | ||
26 | case CAIF_LINK_HIGH_BANDW: | ||
27 | pref = CFPHYPREF_HIGH_BW; | ||
28 | break; | ||
29 | case CAIF_LINK_LOW_LATENCY: | ||
30 | pref = CFPHYPREF_LOW_LAT; | ||
31 | break; | ||
32 | default: | ||
33 | return -EINVAL; | ||
34 | } | ||
35 | dev_info = cfcnfg_get_phyid(cnfg, pref); | ||
36 | if (dev_info == NULL) | ||
37 | return -ENODEV; | ||
38 | l->phyid = dev_info->id; | ||
39 | } | ||
40 | switch (s->protocol) { | ||
41 | case CAIFPROTO_AT: | ||
42 | l->linktype = CFCTRL_SRV_VEI; | ||
43 | if (s->sockaddr.u.at.type == CAIF_ATTYPE_PLAIN) | ||
44 | l->chtype = 0x02; | ||
45 | else | ||
46 | l->chtype = s->sockaddr.u.at.type; | ||
47 | l->endpoint = 0x00; | ||
48 | break; | ||
49 | case CAIFPROTO_DATAGRAM: | ||
50 | l->linktype = CFCTRL_SRV_DATAGRAM; | ||
51 | l->chtype = 0x00; | ||
52 | l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; | ||
53 | break; | ||
54 | case CAIFPROTO_DATAGRAM_LOOP: | ||
55 | l->linktype = CFCTRL_SRV_DATAGRAM; | ||
56 | l->chtype = 0x03; | ||
57 | l->endpoint = 0x00; | ||
58 | l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; | ||
59 | break; | ||
60 | case CAIFPROTO_RFM: | ||
61 | l->linktype = CFCTRL_SRV_RFM; | ||
62 | l->u.datagram.connid = s->sockaddr.u.rfm.connection_id; | ||
63 | strncpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume, | ||
64 | sizeof(l->u.rfm.volume)-1); | ||
65 | l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0; | ||
66 | break; | ||
67 | case CAIFPROTO_UTIL: | ||
68 | l->linktype = CFCTRL_SRV_UTIL; | ||
69 | l->endpoint = 0x00; | ||
70 | l->chtype = 0x00; | ||
71 | strncpy(l->u.utility.name, s->sockaddr.u.util.service, | ||
72 | sizeof(l->u.utility.name)-1); | ||
73 | l->u.utility.name[sizeof(l->u.utility.name)-1] = 0; | ||
74 | caif_assert(sizeof(l->u.utility.name) > 10); | ||
75 | l->u.utility.paramlen = s->param.size; | ||
76 | if (l->u.utility.paramlen > sizeof(l->u.utility.params)) | ||
77 | l->u.utility.paramlen = sizeof(l->u.utility.params); | ||
78 | |||
79 | memcpy(l->u.utility.params, s->param.data, | ||
80 | l->u.utility.paramlen); | ||
81 | |||
82 | break; | ||
83 | case CAIFPROTO_DEBUG: | ||
84 | l->linktype = CFCTRL_SRV_DBG; | ||
85 | l->endpoint = s->sockaddr.u.dbg.service; | ||
86 | l->chtype = s->sockaddr.u.dbg.type; | ||
87 | break; | ||
88 | default: | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | return 0; | ||
92 | } | ||
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 0b586e9d1378..682c0fedf360 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c | |||
@@ -9,50 +9,54 @@ | |||
9 | * and Sakari Ailus <sakari.ailus@nokia.com> | 9 | * and Sakari Ailus <sakari.ailus@nokia.com> |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
13 | |||
12 | #include <linux/version.h> | 14 | #include <linux/version.h> |
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
15 | #include <linux/if_arp.h> | 16 | #include <linux/if_arp.h> |
16 | #include <linux/net.h> | 17 | #include <linux/net.h> |
17 | #include <linux/netdevice.h> | 18 | #include <linux/netdevice.h> |
18 | #include <linux/skbuff.h> | 19 | #include <linux/mutex.h> |
19 | #include <linux/sched.h> | ||
20 | #include <linux/wait.h> | ||
21 | #include <net/netns/generic.h> | 20 | #include <net/netns/generic.h> |
22 | #include <net/net_namespace.h> | 21 | #include <net/net_namespace.h> |
23 | #include <net/pkt_sched.h> | 22 | #include <net/pkt_sched.h> |
24 | #include <net/caif/caif_device.h> | 23 | #include <net/caif/caif_device.h> |
25 | #include <net/caif/caif_dev.h> | ||
26 | #include <net/caif/caif_layer.h> | 24 | #include <net/caif/caif_layer.h> |
27 | #include <net/caif/cfpkt.h> | 25 | #include <net/caif/cfpkt.h> |
28 | #include <net/caif/cfcnfg.h> | 26 | #include <net/caif/cfcnfg.h> |
29 | 27 | ||
30 | MODULE_LICENSE("GPL"); | 28 | MODULE_LICENSE("GPL"); |
31 | #define TIMEOUT (HZ*5) | ||
32 | 29 | ||
33 | /* Used for local tracking of the CAIF net devices */ | 30 | /* Used for local tracking of the CAIF net devices */ |
34 | struct caif_device_entry { | 31 | struct caif_device_entry { |
35 | struct cflayer layer; | 32 | struct cflayer layer; |
36 | struct list_head list; | 33 | struct list_head list; |
37 | atomic_t in_use; | ||
38 | atomic_t state; | ||
39 | u16 phyid; | ||
40 | struct net_device *netdev; | 34 | struct net_device *netdev; |
41 | wait_queue_head_t event; | 35 | int __percpu *pcpu_refcnt; |
42 | }; | 36 | }; |
43 | 37 | ||
44 | struct caif_device_entry_list { | 38 | struct caif_device_entry_list { |
45 | struct list_head list; | 39 | struct list_head list; |
46 | /* Protects simulanous deletes in list */ | 40 | /* Protects simulanous deletes in list */ |
47 | spinlock_t lock; | 41 | struct mutex lock; |
48 | }; | 42 | }; |
49 | 43 | ||
50 | struct caif_net { | 44 | struct caif_net { |
45 | struct cfcnfg *cfg; | ||
51 | struct caif_device_entry_list caifdevs; | 46 | struct caif_device_entry_list caifdevs; |
52 | }; | 47 | }; |
53 | 48 | ||
54 | static int caif_net_id; | 49 | static int caif_net_id; |
55 | static struct cfcnfg *cfg; | 50 | |
51 | struct cfcnfg *get_cfcnfg(struct net *net) | ||
52 | { | ||
53 | struct caif_net *caifn; | ||
54 | BUG_ON(!net); | ||
55 | caifn = net_generic(net, caif_net_id); | ||
56 | BUG_ON(!caifn); | ||
57 | return caifn->cfg; | ||
58 | } | ||
59 | EXPORT_SYMBOL(get_cfcnfg); | ||
56 | 60 | ||
57 | static struct caif_device_entry_list *caif_device_list(struct net *net) | 61 | static struct caif_device_entry_list *caif_device_list(struct net *net) |
58 | { | 62 | { |
@@ -63,19 +67,39 @@ static struct caif_device_entry_list *caif_device_list(struct net *net) | |||
63 | return &caifn->caifdevs; | 67 | return &caifn->caifdevs; |
64 | } | 68 | } |
65 | 69 | ||
70 | static void caifd_put(struct caif_device_entry *e) | ||
71 | { | ||
72 | irqsafe_cpu_dec(*e->pcpu_refcnt); | ||
73 | } | ||
74 | |||
75 | static void caifd_hold(struct caif_device_entry *e) | ||
76 | { | ||
77 | irqsafe_cpu_inc(*e->pcpu_refcnt); | ||
78 | } | ||
79 | |||
80 | static int caifd_refcnt_read(struct caif_device_entry *e) | ||
81 | { | ||
82 | int i, refcnt = 0; | ||
83 | for_each_possible_cpu(i) | ||
84 | refcnt += *per_cpu_ptr(e->pcpu_refcnt, i); | ||
85 | return refcnt; | ||
86 | } | ||
87 | |||
66 | /* Allocate new CAIF device. */ | 88 | /* Allocate new CAIF device. */ |
67 | static struct caif_device_entry *caif_device_alloc(struct net_device *dev) | 89 | static struct caif_device_entry *caif_device_alloc(struct net_device *dev) |
68 | { | 90 | { |
69 | struct caif_device_entry_list *caifdevs; | 91 | struct caif_device_entry_list *caifdevs; |
70 | struct caif_device_entry *caifd; | 92 | struct caif_device_entry *caifd; |
93 | |||
71 | caifdevs = caif_device_list(dev_net(dev)); | 94 | caifdevs = caif_device_list(dev_net(dev)); |
72 | BUG_ON(!caifdevs); | 95 | BUG_ON(!caifdevs); |
96 | |||
73 | caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC); | 97 | caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC); |
74 | if (!caifd) | 98 | if (!caifd) |
75 | return NULL; | 99 | return NULL; |
100 | caifd->pcpu_refcnt = alloc_percpu(int); | ||
76 | caifd->netdev = dev; | 101 | caifd->netdev = dev; |
77 | list_add(&caifd->list, &caifdevs->list); | 102 | dev_hold(dev); |
78 | init_waitqueue_head(&caifd->event); | ||
79 | return caifd; | 103 | return caifd; |
80 | } | 104 | } |
81 | 105 | ||
@@ -85,98 +109,65 @@ static struct caif_device_entry *caif_get(struct net_device *dev) | |||
85 | caif_device_list(dev_net(dev)); | 109 | caif_device_list(dev_net(dev)); |
86 | struct caif_device_entry *caifd; | 110 | struct caif_device_entry *caifd; |
87 | BUG_ON(!caifdevs); | 111 | BUG_ON(!caifdevs); |
88 | list_for_each_entry(caifd, &caifdevs->list, list) { | 112 | list_for_each_entry_rcu(caifd, &caifdevs->list, list) { |
89 | if (caifd->netdev == dev) | 113 | if (caifd->netdev == dev) |
90 | return caifd; | 114 | return caifd; |
91 | } | 115 | } |
92 | return NULL; | 116 | return NULL; |
93 | } | 117 | } |
94 | 118 | ||
95 | static void caif_device_destroy(struct net_device *dev) | ||
96 | { | ||
97 | struct caif_device_entry_list *caifdevs = | ||
98 | caif_device_list(dev_net(dev)); | ||
99 | struct caif_device_entry *caifd; | ||
100 | ASSERT_RTNL(); | ||
101 | if (dev->type != ARPHRD_CAIF) | ||
102 | return; | ||
103 | |||
104 | spin_lock_bh(&caifdevs->lock); | ||
105 | caifd = caif_get(dev); | ||
106 | if (caifd == NULL) { | ||
107 | spin_unlock_bh(&caifdevs->lock); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | list_del(&caifd->list); | ||
112 | spin_unlock_bh(&caifdevs->lock); | ||
113 | |||
114 | kfree(caifd); | ||
115 | } | ||
116 | |||
117 | static int transmit(struct cflayer *layer, struct cfpkt *pkt) | 119 | static int transmit(struct cflayer *layer, struct cfpkt *pkt) |
118 | { | 120 | { |
121 | int err; | ||
119 | struct caif_device_entry *caifd = | 122 | struct caif_device_entry *caifd = |
120 | container_of(layer, struct caif_device_entry, layer); | 123 | container_of(layer, struct caif_device_entry, layer); |
121 | struct sk_buff *skb, *skb2; | 124 | struct sk_buff *skb; |
122 | int ret = -EINVAL; | 125 | |
123 | skb = cfpkt_tonative(pkt); | 126 | skb = cfpkt_tonative(pkt); |
124 | skb->dev = caifd->netdev; | 127 | skb->dev = caifd->netdev; |
125 | /* | ||
126 | * Don't allow SKB to be destroyed upon error, but signal resend | ||
127 | * notification to clients. We can't rely on the return value as | ||
128 | * congestion (NET_XMIT_CN) sometimes drops the packet, sometimes don't. | ||
129 | */ | ||
130 | if (netif_queue_stopped(caifd->netdev)) | ||
131 | return -EAGAIN; | ||
132 | skb2 = skb_get(skb); | ||
133 | |||
134 | ret = dev_queue_xmit(skb2); | ||
135 | |||
136 | if (!ret) | ||
137 | kfree_skb(skb); | ||
138 | else | ||
139 | return -EAGAIN; | ||
140 | 128 | ||
141 | return 0; | 129 | err = dev_queue_xmit(skb); |
142 | } | 130 | if (err > 0) |
131 | err = -EIO; | ||
143 | 132 | ||
144 | static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) | 133 | return err; |
145 | { | ||
146 | struct caif_device_entry *caifd; | ||
147 | struct caif_dev_common *caifdev; | ||
148 | caifd = container_of(layr, struct caif_device_entry, layer); | ||
149 | caifdev = netdev_priv(caifd->netdev); | ||
150 | if (ctrl == _CAIF_MODEMCMD_PHYIF_USEFULL) { | ||
151 | atomic_set(&caifd->in_use, 1); | ||
152 | wake_up_interruptible(&caifd->event); | ||
153 | |||
154 | } else if (ctrl == _CAIF_MODEMCMD_PHYIF_USELESS) { | ||
155 | atomic_set(&caifd->in_use, 0); | ||
156 | wake_up_interruptible(&caifd->event); | ||
157 | } | ||
158 | return 0; | ||
159 | } | 134 | } |
160 | 135 | ||
161 | /* | 136 | /* |
162 | * Stuff received packets to associated sockets. | 137 | * Stuff received packets into the CAIF stack. |
163 | * On error, returns non-zero and releases the skb. | 138 | * On error, returns non-zero and releases the skb. |
164 | */ | 139 | */ |
165 | static int receive(struct sk_buff *skb, struct net_device *dev, | 140 | static int receive(struct sk_buff *skb, struct net_device *dev, |
166 | struct packet_type *pkttype, struct net_device *orig_dev) | 141 | struct packet_type *pkttype, struct net_device *orig_dev) |
167 | { | 142 | { |
168 | struct net *net; | ||
169 | struct cfpkt *pkt; | 143 | struct cfpkt *pkt; |
170 | struct caif_device_entry *caifd; | 144 | struct caif_device_entry *caifd; |
171 | net = dev_net(dev); | 145 | int err; |
146 | |||
172 | pkt = cfpkt_fromnative(CAIF_DIR_IN, skb); | 147 | pkt = cfpkt_fromnative(CAIF_DIR_IN, skb); |
148 | |||
149 | rcu_read_lock(); | ||
173 | caifd = caif_get(dev); | 150 | caifd = caif_get(dev); |
174 | if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) | ||
175 | return NET_RX_DROP; | ||
176 | 151 | ||
177 | if (caifd->layer.up->receive(caifd->layer.up, pkt)) | 152 | if (!caifd || !caifd->layer.up || !caifd->layer.up->receive || |
153 | !netif_oper_up(caifd->netdev)) { | ||
154 | rcu_read_unlock(); | ||
155 | kfree_skb(skb); | ||
178 | return NET_RX_DROP; | 156 | return NET_RX_DROP; |
157 | } | ||
179 | 158 | ||
159 | /* Hold reference to netdevice while using CAIF stack */ | ||
160 | caifd_hold(caifd); | ||
161 | rcu_read_unlock(); | ||
162 | |||
163 | err = caifd->layer.up->receive(caifd->layer.up, pkt); | ||
164 | |||
165 | /* For -EILSEQ the packet is not freed so so it now */ | ||
166 | if (err == -EILSEQ) | ||
167 | cfpkt_destroy(pkt); | ||
168 | |||
169 | /* Release reference to stack upwards */ | ||
170 | caifd_put(caifd); | ||
180 | return 0; | 171 | return 0; |
181 | } | 172 | } |
182 | 173 | ||
@@ -187,15 +178,25 @@ static struct packet_type caif_packet_type __read_mostly = { | |||
187 | 178 | ||
188 | static void dev_flowctrl(struct net_device *dev, int on) | 179 | static void dev_flowctrl(struct net_device *dev, int on) |
189 | { | 180 | { |
190 | struct caif_device_entry *caifd = caif_get(dev); | 181 | struct caif_device_entry *caifd; |
191 | if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) | 182 | |
183 | rcu_read_lock(); | ||
184 | |||
185 | caifd = caif_get(dev); | ||
186 | if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) { | ||
187 | rcu_read_unlock(); | ||
192 | return; | 188 | return; |
189 | } | ||
190 | |||
191 | caifd_hold(caifd); | ||
192 | rcu_read_unlock(); | ||
193 | 193 | ||
194 | caifd->layer.up->ctrlcmd(caifd->layer.up, | 194 | caifd->layer.up->ctrlcmd(caifd->layer.up, |
195 | on ? | 195 | on ? |
196 | _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND : | 196 | _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND : |
197 | _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, | 197 | _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, |
198 | caifd->layer.id); | 198 | caifd->layer.id); |
199 | caifd_put(caifd); | ||
199 | } | 200 | } |
200 | 201 | ||
201 | /* notify Caif of device events */ | 202 | /* notify Caif of device events */ |
@@ -206,38 +207,28 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, | |||
206 | struct caif_device_entry *caifd = NULL; | 207 | struct caif_device_entry *caifd = NULL; |
207 | struct caif_dev_common *caifdev; | 208 | struct caif_dev_common *caifdev; |
208 | enum cfcnfg_phy_preference pref; | 209 | enum cfcnfg_phy_preference pref; |
209 | int res = -EINVAL; | ||
210 | enum cfcnfg_phy_type phy_type; | 210 | enum cfcnfg_phy_type phy_type; |
211 | struct cfcnfg *cfg; | ||
212 | struct caif_device_entry_list *caifdevs = | ||
213 | caif_device_list(dev_net(dev)); | ||
211 | 214 | ||
212 | if (dev->type != ARPHRD_CAIF) | 215 | if (dev->type != ARPHRD_CAIF) |
213 | return 0; | 216 | return 0; |
214 | 217 | ||
218 | cfg = get_cfcnfg(dev_net(dev)); | ||
219 | if (cfg == NULL) | ||
220 | return 0; | ||
221 | |||
215 | switch (what) { | 222 | switch (what) { |
216 | case NETDEV_REGISTER: | 223 | case NETDEV_REGISTER: |
217 | pr_info("CAIF: %s():register %s\n", __func__, dev->name); | ||
218 | caifd = caif_device_alloc(dev); | 224 | caifd = caif_device_alloc(dev); |
219 | if (caifd == NULL) | 225 | if (!caifd) |
220 | break; | 226 | return 0; |
227 | |||
221 | caifdev = netdev_priv(dev); | 228 | caifdev = netdev_priv(dev); |
222 | caifdev->flowctrl = dev_flowctrl; | 229 | caifdev->flowctrl = dev_flowctrl; |
223 | atomic_set(&caifd->state, what); | ||
224 | res = 0; | ||
225 | break; | ||
226 | 230 | ||
227 | case NETDEV_UP: | ||
228 | pr_info("CAIF: %s(): up %s\n", __func__, dev->name); | ||
229 | caifd = caif_get(dev); | ||
230 | if (caifd == NULL) | ||
231 | break; | ||
232 | caifdev = netdev_priv(dev); | ||
233 | if (atomic_read(&caifd->state) == NETDEV_UP) { | ||
234 | pr_info("CAIF: %s():%s already up\n", | ||
235 | __func__, dev->name); | ||
236 | break; | ||
237 | } | ||
238 | atomic_set(&caifd->state, what); | ||
239 | caifd->layer.transmit = transmit; | 231 | caifd->layer.transmit = transmit; |
240 | caifd->layer.modemcmd = modemcmd; | ||
241 | 232 | ||
242 | if (caifdev->use_frag) | 233 | if (caifdev->use_frag) |
243 | phy_type = CFPHYTYPE_FRAG; | 234 | phy_type = CFPHYTYPE_FRAG; |
@@ -255,61 +246,94 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, | |||
255 | pref = CFPHYPREF_HIGH_BW; | 246 | pref = CFPHYPREF_HIGH_BW; |
256 | break; | 247 | break; |
257 | } | 248 | } |
258 | dev_hold(dev); | 249 | strncpy(caifd->layer.name, dev->name, |
259 | cfcnfg_add_phy_layer(get_caif_conf(), | 250 | sizeof(caifd->layer.name) - 1); |
251 | caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0; | ||
252 | |||
253 | mutex_lock(&caifdevs->lock); | ||
254 | list_add_rcu(&caifd->list, &caifdevs->list); | ||
255 | |||
256 | cfcnfg_add_phy_layer(cfg, | ||
260 | phy_type, | 257 | phy_type, |
261 | dev, | 258 | dev, |
262 | &caifd->layer, | 259 | &caifd->layer, |
263 | &caifd->phyid, | ||
264 | pref, | 260 | pref, |
265 | caifdev->use_fcs, | 261 | caifdev->use_fcs, |
266 | caifdev->use_stx); | 262 | caifdev->use_stx); |
267 | strncpy(caifd->layer.name, dev->name, | 263 | mutex_unlock(&caifdevs->lock); |
268 | sizeof(caifd->layer.name) - 1); | ||
269 | caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0; | ||
270 | break; | 264 | break; |
271 | 265 | ||
272 | case NETDEV_GOING_DOWN: | 266 | case NETDEV_UP: |
267 | rcu_read_lock(); | ||
268 | |||
273 | caifd = caif_get(dev); | 269 | caifd = caif_get(dev); |
274 | if (caifd == NULL) | 270 | if (caifd == NULL) { |
271 | rcu_read_unlock(); | ||
275 | break; | 272 | break; |
276 | pr_info("CAIF: %s():going down %s\n", __func__, dev->name); | 273 | } |
277 | 274 | ||
278 | if (atomic_read(&caifd->state) == NETDEV_GOING_DOWN || | 275 | cfcnfg_set_phy_state(cfg, &caifd->layer, true); |
279 | atomic_read(&caifd->state) == NETDEV_DOWN) | 276 | rcu_read_unlock(); |
280 | break; | 277 | |
278 | break; | ||
279 | |||
280 | case NETDEV_DOWN: | ||
281 | rcu_read_lock(); | ||
281 | 282 | ||
282 | atomic_set(&caifd->state, what); | 283 | caifd = caif_get(dev); |
283 | if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) | 284 | if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) { |
285 | rcu_read_unlock(); | ||
284 | return -EINVAL; | 286 | return -EINVAL; |
287 | } | ||
288 | |||
289 | cfcnfg_set_phy_state(cfg, &caifd->layer, false); | ||
290 | caifd_hold(caifd); | ||
291 | rcu_read_unlock(); | ||
292 | |||
285 | caifd->layer.up->ctrlcmd(caifd->layer.up, | 293 | caifd->layer.up->ctrlcmd(caifd->layer.up, |
286 | _CAIF_CTRLCMD_PHYIF_DOWN_IND, | 294 | _CAIF_CTRLCMD_PHYIF_DOWN_IND, |
287 | caifd->layer.id); | 295 | caifd->layer.id); |
288 | might_sleep(); | 296 | caifd_put(caifd); |
289 | res = wait_event_interruptible_timeout(caifd->event, | ||
290 | atomic_read(&caifd->in_use) == 0, | ||
291 | TIMEOUT); | ||
292 | break; | 297 | break; |
293 | 298 | ||
294 | case NETDEV_DOWN: | 299 | case NETDEV_UNREGISTER: |
300 | mutex_lock(&caifdevs->lock); | ||
301 | |||
295 | caifd = caif_get(dev); | 302 | caifd = caif_get(dev); |
296 | if (caifd == NULL) | 303 | if (caifd == NULL) { |
304 | mutex_unlock(&caifdevs->lock); | ||
297 | break; | 305 | break; |
298 | pr_info("CAIF: %s(): down %s\n", __func__, dev->name); | 306 | } |
299 | if (atomic_read(&caifd->in_use)) | 307 | list_del_rcu(&caifd->list); |
300 | pr_warning("CAIF: %s(): " | 308 | |
301 | "Unregistering an active CAIF device: %s\n", | 309 | /* |
302 | __func__, dev->name); | 310 | * NETDEV_UNREGISTER is called repeatedly until all reference |
303 | cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer); | 311 | * counts for the net-device are released. If references to |
304 | dev_put(dev); | 312 | * caifd is taken, simply ignore NETDEV_UNREGISTER and wait for |
305 | atomic_set(&caifd->state, what); | 313 | * the next call to NETDEV_UNREGISTER. |
306 | break; | 314 | * |
315 | * If any packets are in flight down the CAIF Stack, | ||
316 | * cfcnfg_del_phy_layer will return nonzero. | ||
317 | * If no packets are in flight, the CAIF Stack associated | ||
318 | * with the net-device un-registering is freed. | ||
319 | */ | ||
320 | |||
321 | if (caifd_refcnt_read(caifd) != 0 || | ||
322 | cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0) { | ||
323 | |||
324 | pr_info("Wait for device inuse\n"); | ||
325 | /* Enrole device if CAIF Stack is still in use */ | ||
326 | list_add_rcu(&caifd->list, &caifdevs->list); | ||
327 | mutex_unlock(&caifdevs->lock); | ||
328 | break; | ||
329 | } | ||
307 | 330 | ||
308 | case NETDEV_UNREGISTER: | 331 | synchronize_rcu(); |
309 | caifd = caif_get(dev); | 332 | dev_put(caifd->netdev); |
310 | pr_info("CAIF: %s(): unregister %s\n", __func__, dev->name); | 333 | free_percpu(caifd->pcpu_refcnt); |
311 | atomic_set(&caifd->state, what); | 334 | kfree(caifd); |
312 | caif_device_destroy(dev); | 335 | |
336 | mutex_unlock(&caifdevs->lock); | ||
313 | break; | 337 | break; |
314 | } | 338 | } |
315 | return 0; | 339 | return 0; |
@@ -320,61 +344,60 @@ static struct notifier_block caif_device_notifier = { | |||
320 | .priority = 0, | 344 | .priority = 0, |
321 | }; | 345 | }; |
322 | 346 | ||
323 | |||
324 | struct cfcnfg *get_caif_conf(void) | ||
325 | { | ||
326 | return cfg; | ||
327 | } | ||
328 | EXPORT_SYMBOL(get_caif_conf); | ||
329 | |||
330 | int caif_connect_client(struct caif_connect_request *conn_req, | ||
331 | struct cflayer *client_layer, int *ifindex, | ||
332 | int *headroom, int *tailroom) | ||
333 | { | ||
334 | struct cfctrl_link_param param; | ||
335 | int ret; | ||
336 | ret = connect_req_to_link_param(get_caif_conf(), conn_req, ¶m); | ||
337 | if (ret) | ||
338 | return ret; | ||
339 | /* Hook up the adaptation layer. */ | ||
340 | return cfcnfg_add_adaptation_layer(get_caif_conf(), ¶m, | ||
341 | client_layer, ifindex, | ||
342 | headroom, tailroom); | ||
343 | } | ||
344 | EXPORT_SYMBOL(caif_connect_client); | ||
345 | |||
346 | int caif_disconnect_client(struct cflayer *adap_layer) | ||
347 | { | ||
348 | return cfcnfg_disconn_adapt_layer(get_caif_conf(), adap_layer); | ||
349 | } | ||
350 | EXPORT_SYMBOL(caif_disconnect_client); | ||
351 | |||
352 | void caif_release_client(struct cflayer *adap_layer) | ||
353 | { | ||
354 | cfcnfg_release_adap_layer(adap_layer); | ||
355 | } | ||
356 | EXPORT_SYMBOL(caif_release_client); | ||
357 | |||
358 | /* Per-namespace Caif devices handling */ | 347 | /* Per-namespace Caif devices handling */ |
359 | static int caif_init_net(struct net *net) | 348 | static int caif_init_net(struct net *net) |
360 | { | 349 | { |
361 | struct caif_net *caifn = net_generic(net, caif_net_id); | 350 | struct caif_net *caifn = net_generic(net, caif_net_id); |
351 | BUG_ON(!caifn); | ||
362 | INIT_LIST_HEAD(&caifn->caifdevs.list); | 352 | INIT_LIST_HEAD(&caifn->caifdevs.list); |
363 | spin_lock_init(&caifn->caifdevs.lock); | 353 | mutex_init(&caifn->caifdevs.lock); |
354 | |||
355 | caifn->cfg = cfcnfg_create(); | ||
356 | if (!caifn->cfg) { | ||
357 | pr_warn("can't create cfcnfg\n"); | ||
358 | return -ENOMEM; | ||
359 | } | ||
360 | |||
364 | return 0; | 361 | return 0; |
365 | } | 362 | } |
366 | 363 | ||
367 | static void caif_exit_net(struct net *net) | 364 | static void caif_exit_net(struct net *net) |
368 | { | 365 | { |
369 | struct net_device *dev; | 366 | struct caif_device_entry *caifd, *tmp; |
370 | int res; | 367 | struct caif_device_entry_list *caifdevs = |
368 | caif_device_list(net); | ||
369 | struct cfcnfg *cfg; | ||
370 | |||
371 | rtnl_lock(); | 371 | rtnl_lock(); |
372 | for_each_netdev(net, dev) { | 372 | mutex_lock(&caifdevs->lock); |
373 | if (dev->type != ARPHRD_CAIF) | 373 | |
374 | continue; | 374 | cfg = get_cfcnfg(net); |
375 | res = dev_close(dev); | 375 | if (cfg == NULL) { |
376 | caif_device_destroy(dev); | 376 | mutex_unlock(&caifdevs->lock); |
377 | return; | ||
377 | } | 378 | } |
379 | |||
380 | list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) { | ||
381 | int i = 0; | ||
382 | list_del_rcu(&caifd->list); | ||
383 | cfcnfg_set_phy_state(cfg, &caifd->layer, false); | ||
384 | |||
385 | while (i < 10 && | ||
386 | (caifd_refcnt_read(caifd) != 0 || | ||
387 | cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0)) { | ||
388 | |||
389 | pr_info("Wait for device inuse\n"); | ||
390 | msleep(250); | ||
391 | i++; | ||
392 | } | ||
393 | synchronize_rcu(); | ||
394 | dev_put(caifd->netdev); | ||
395 | free_percpu(caifd->pcpu_refcnt); | ||
396 | kfree(caifd); | ||
397 | } | ||
398 | cfcnfg_remove(cfg); | ||
399 | |||
400 | mutex_unlock(&caifdevs->lock); | ||
378 | rtnl_unlock(); | 401 | rtnl_unlock(); |
379 | } | 402 | } |
380 | 403 | ||
@@ -389,32 +412,23 @@ static struct pernet_operations caif_net_ops = { | |||
389 | static int __init caif_device_init(void) | 412 | static int __init caif_device_init(void) |
390 | { | 413 | { |
391 | int result; | 414 | int result; |
392 | cfg = cfcnfg_create(); | 415 | |
393 | if (!cfg) { | ||
394 | pr_warning("CAIF: %s(): can't create cfcnfg.\n", __func__); | ||
395 | goto err_cfcnfg_create_failed; | ||
396 | } | ||
397 | result = register_pernet_device(&caif_net_ops); | 416 | result = register_pernet_device(&caif_net_ops); |
398 | 417 | ||
399 | if (result) { | 418 | if (result) |
400 | kfree(cfg); | ||
401 | cfg = NULL; | ||
402 | return result; | 419 | return result; |
403 | } | 420 | |
404 | dev_add_pack(&caif_packet_type); | ||
405 | register_netdevice_notifier(&caif_device_notifier); | 421 | register_netdevice_notifier(&caif_device_notifier); |
422 | dev_add_pack(&caif_packet_type); | ||
406 | 423 | ||
407 | return result; | 424 | return result; |
408 | err_cfcnfg_create_failed: | ||
409 | return -ENODEV; | ||
410 | } | 425 | } |
411 | 426 | ||
412 | static void __exit caif_device_exit(void) | 427 | static void __exit caif_device_exit(void) |
413 | { | 428 | { |
414 | dev_remove_pack(&caif_packet_type); | ||
415 | unregister_pernet_device(&caif_net_ops); | 429 | unregister_pernet_device(&caif_net_ops); |
416 | unregister_netdevice_notifier(&caif_device_notifier); | 430 | unregister_netdevice_notifier(&caif_device_notifier); |
417 | cfcnfg_remove(cfg); | 431 | dev_remove_pack(&caif_packet_type); |
418 | } | 432 | } |
419 | 433 | ||
420 | module_init(caif_device_init); | 434 | module_init(caif_device_init); |
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 4bf28f25f368..a98628086452 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/fs.h> | 9 | #include <linux/fs.h> |
8 | #include <linux/init.h> | 10 | #include <linux/init.h> |
9 | #include <linux/module.h> | 11 | #include <linux/module.h> |
@@ -15,10 +17,9 @@ | |||
15 | #include <linux/poll.h> | 17 | #include <linux/poll.h> |
16 | #include <linux/tcp.h> | 18 | #include <linux/tcp.h> |
17 | #include <linux/uaccess.h> | 19 | #include <linux/uaccess.h> |
18 | #include <linux/mutex.h> | ||
19 | #include <linux/debugfs.h> | 20 | #include <linux/debugfs.h> |
20 | #include <linux/caif/caif_socket.h> | 21 | #include <linux/caif/caif_socket.h> |
21 | #include <asm/atomic.h> | 22 | #include <linux/atomic.h> |
22 | #include <net/sock.h> | 23 | #include <net/sock.h> |
23 | #include <net/tcp_states.h> | 24 | #include <net/tcp_states.h> |
24 | #include <net/caif/caif_layer.h> | 25 | #include <net/caif/caif_layer.h> |
@@ -28,9 +29,6 @@ | |||
28 | MODULE_LICENSE("GPL"); | 29 | MODULE_LICENSE("GPL"); |
29 | MODULE_ALIAS_NETPROTO(AF_CAIF); | 30 | MODULE_ALIAS_NETPROTO(AF_CAIF); |
30 | 31 | ||
31 | #define CAIF_DEF_SNDBUF (4096*10) | ||
32 | #define CAIF_DEF_RCVBUF (4096*100) | ||
33 | |||
34 | /* | 32 | /* |
35 | * CAIF state is re-using the TCP socket states. | 33 | * CAIF state is re-using the TCP socket states. |
36 | * caif_states stored in sk_state reflect the state as reported by | 34 | * caif_states stored in sk_state reflect the state as reported by |
@@ -50,6 +48,7 @@ static struct dentry *debugfsdir; | |||
50 | #ifdef CONFIG_DEBUG_FS | 48 | #ifdef CONFIG_DEBUG_FS |
51 | struct debug_fs_counter { | 49 | struct debug_fs_counter { |
52 | atomic_t caif_nr_socks; | 50 | atomic_t caif_nr_socks; |
51 | atomic_t caif_sock_create; | ||
53 | atomic_t num_connect_req; | 52 | atomic_t num_connect_req; |
54 | atomic_t num_connect_resp; | 53 | atomic_t num_connect_resp; |
55 | atomic_t num_connect_fail_resp; | 54 | atomic_t num_connect_fail_resp; |
@@ -61,11 +60,11 @@ struct debug_fs_counter { | |||
61 | atomic_t num_rx_flow_on; | 60 | atomic_t num_rx_flow_on; |
62 | }; | 61 | }; |
63 | static struct debug_fs_counter cnt; | 62 | static struct debug_fs_counter cnt; |
64 | #define dbfs_atomic_inc(v) atomic_inc(v) | 63 | #define dbfs_atomic_inc(v) atomic_inc_return(v) |
65 | #define dbfs_atomic_dec(v) atomic_dec(v) | 64 | #define dbfs_atomic_dec(v) atomic_dec_return(v) |
66 | #else | 65 | #else |
67 | #define dbfs_atomic_inc(v) | 66 | #define dbfs_atomic_inc(v) 0 |
68 | #define dbfs_atomic_dec(v) | 67 | #define dbfs_atomic_dec(v) 0 |
69 | #endif | 68 | #endif |
70 | 69 | ||
71 | struct caifsock { | 70 | struct caifsock { |
@@ -157,11 +156,10 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
157 | 156 | ||
158 | if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= | 157 | if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= |
159 | (unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) { | 158 | (unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) { |
160 | trace_printk("CAIF: %s():" | 159 | if (net_ratelimit()) |
161 | " sending flow OFF (queue len = %d %d)\n", | 160 | pr_debug("sending flow OFF (queue len = %d %d)\n", |
162 | __func__, | 161 | atomic_read(&cf_sk->sk.sk_rmem_alloc), |
163 | atomic_read(&cf_sk->sk.sk_rmem_alloc), | 162 | sk_rcvbuf_lowwater(cf_sk)); |
164 | sk_rcvbuf_lowwater(cf_sk)); | ||
165 | set_rx_flow_off(cf_sk); | 163 | set_rx_flow_off(cf_sk); |
166 | dbfs_atomic_inc(&cnt.num_rx_flow_off); | 164 | dbfs_atomic_inc(&cnt.num_rx_flow_off); |
167 | caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); | 165 | caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); |
@@ -172,9 +170,8 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
172 | return err; | 170 | return err; |
173 | if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) { | 171 | if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) { |
174 | set_rx_flow_off(cf_sk); | 172 | set_rx_flow_off(cf_sk); |
175 | trace_printk("CAIF: %s():" | 173 | if (net_ratelimit()) |
176 | " sending flow OFF due to rmem_schedule\n", | 174 | pr_debug("sending flow OFF due to rmem_schedule\n"); |
177 | __func__); | ||
178 | dbfs_atomic_inc(&cnt.num_rx_flow_off); | 175 | dbfs_atomic_inc(&cnt.num_rx_flow_off); |
179 | caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); | 176 | caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); |
180 | } | 177 | } |
@@ -208,13 +205,25 @@ static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt) | |||
208 | skb = cfpkt_tonative(pkt); | 205 | skb = cfpkt_tonative(pkt); |
209 | 206 | ||
210 | if (unlikely(cf_sk->sk.sk_state != CAIF_CONNECTED)) { | 207 | if (unlikely(cf_sk->sk.sk_state != CAIF_CONNECTED)) { |
211 | cfpkt_destroy(pkt); | 208 | kfree_skb(skb); |
212 | return 0; | 209 | return 0; |
213 | } | 210 | } |
214 | caif_queue_rcv_skb(&cf_sk->sk, skb); | 211 | caif_queue_rcv_skb(&cf_sk->sk, skb); |
215 | return 0; | 212 | return 0; |
216 | } | 213 | } |
217 | 214 | ||
215 | static void cfsk_hold(struct cflayer *layr) | ||
216 | { | ||
217 | struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); | ||
218 | sock_hold(&cf_sk->sk); | ||
219 | } | ||
220 | |||
221 | static void cfsk_put(struct cflayer *layr) | ||
222 | { | ||
223 | struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); | ||
224 | sock_put(&cf_sk->sk); | ||
225 | } | ||
226 | |||
218 | /* Packet Control Callback function called from CAIF */ | 227 | /* Packet Control Callback function called from CAIF */ |
219 | static void caif_ctrl_cb(struct cflayer *layr, | 228 | static void caif_ctrl_cb(struct cflayer *layr, |
220 | enum caif_ctrlcmd flow, | 229 | enum caif_ctrlcmd flow, |
@@ -238,6 +247,8 @@ static void caif_ctrl_cb(struct cflayer *layr, | |||
238 | 247 | ||
239 | case CAIF_CTRLCMD_INIT_RSP: | 248 | case CAIF_CTRLCMD_INIT_RSP: |
240 | /* We're now connected */ | 249 | /* We're now connected */ |
250 | caif_client_register_refcnt(&cf_sk->layer, | ||
251 | cfsk_hold, cfsk_put); | ||
241 | dbfs_atomic_inc(&cnt.num_connect_resp); | 252 | dbfs_atomic_inc(&cnt.num_connect_resp); |
242 | cf_sk->sk.sk_state = CAIF_CONNECTED; | 253 | cf_sk->sk.sk_state = CAIF_CONNECTED; |
243 | set_tx_flow_on(cf_sk); | 254 | set_tx_flow_on(cf_sk); |
@@ -248,7 +259,6 @@ static void caif_ctrl_cb(struct cflayer *layr, | |||
248 | /* We're now disconnected */ | 259 | /* We're now disconnected */ |
249 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; | 260 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; |
250 | cf_sk->sk.sk_state_change(&cf_sk->sk); | 261 | cf_sk->sk.sk_state_change(&cf_sk->sk); |
251 | cfcnfg_release_adap_layer(&cf_sk->layer); | ||
252 | break; | 262 | break; |
253 | 263 | ||
254 | case CAIF_CTRLCMD_INIT_FAIL_RSP: | 264 | case CAIF_CTRLCMD_INIT_FAIL_RSP: |
@@ -275,8 +285,7 @@ static void caif_ctrl_cb(struct cflayer *layr, | |||
275 | break; | 285 | break; |
276 | 286 | ||
277 | default: | 287 | default: |
278 | pr_debug("CAIF: %s(): Unexpected flow command %d\n", | 288 | pr_debug("Unexpected flow command %d\n", flow); |
279 | __func__, flow); | ||
280 | } | 289 | } |
281 | } | 290 | } |
282 | 291 | ||
@@ -526,44 +535,14 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk, | |||
526 | int noblock, long timeo) | 535 | int noblock, long timeo) |
527 | { | 536 | { |
528 | struct cfpkt *pkt; | 537 | struct cfpkt *pkt; |
529 | int ret, loopcnt = 0; | ||
530 | 538 | ||
531 | pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb); | 539 | pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb); |
532 | memset(cfpkt_info(pkt), 0, sizeof(struct caif_payload_info)); | 540 | memset(skb->cb, 0, sizeof(struct caif_payload_info)); |
533 | do { | ||
534 | 541 | ||
535 | ret = -ETIMEDOUT; | 542 | if (cf_sk->layer.dn == NULL) |
543 | return -EINVAL; | ||
536 | 544 | ||
537 | /* Slight paranoia, probably not needed. */ | 545 | return cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt); |
538 | if (unlikely(loopcnt++ > 1000)) { | ||
539 | pr_warning("CAIF: %s(): transmit retries failed," | ||
540 | " error = %d\n", __func__, ret); | ||
541 | break; | ||
542 | } | ||
543 | |||
544 | if (cf_sk->layer.dn != NULL) | ||
545 | ret = cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt); | ||
546 | if (likely(ret >= 0)) | ||
547 | break; | ||
548 | /* if transmit return -EAGAIN, then retry */ | ||
549 | if (noblock && ret == -EAGAIN) | ||
550 | break; | ||
551 | timeo = caif_wait_for_flow_on(cf_sk, 0, timeo, &ret); | ||
552 | if (signal_pending(current)) { | ||
553 | ret = sock_intr_errno(timeo); | ||
554 | break; | ||
555 | } | ||
556 | if (ret) | ||
557 | break; | ||
558 | if (cf_sk->sk.sk_state != CAIF_CONNECTED || | ||
559 | sock_flag(&cf_sk->sk, SOCK_DEAD) || | ||
560 | (cf_sk->sk.sk_shutdown & RCV_SHUTDOWN)) { | ||
561 | ret = -EPIPE; | ||
562 | cf_sk->sk.sk_err = EPIPE; | ||
563 | break; | ||
564 | } | ||
565 | } while (ret == -EAGAIN); | ||
566 | return ret; | ||
567 | } | 546 | } |
568 | 547 | ||
569 | /* Copied from af_unix:unix_dgram_sendmsg, and adapted to CAIF */ | 548 | /* Copied from af_unix:unix_dgram_sendmsg, and adapted to CAIF */ |
@@ -628,7 +607,9 @@ static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
628 | goto err; | 607 | goto err; |
629 | ret = transmit_skb(skb, cf_sk, noblock, timeo); | 608 | ret = transmit_skb(skb, cf_sk, noblock, timeo); |
630 | if (ret < 0) | 609 | if (ret < 0) |
631 | goto err; | 610 | /* skb is already freed */ |
611 | return ret; | ||
612 | |||
632 | return len; | 613 | return len; |
633 | err: | 614 | err: |
634 | kfree_skb(skb); | 615 | kfree_skb(skb); |
@@ -724,8 +705,7 @@ static int setsockopt(struct socket *sock, | |||
724 | { | 705 | { |
725 | struct sock *sk = sock->sk; | 706 | struct sock *sk = sock->sk; |
726 | struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); | 707 | struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); |
727 | int prio, linksel; | 708 | int linksel; |
728 | struct ifreq ifreq; | ||
729 | 709 | ||
730 | if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED) | 710 | if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED) |
731 | return -ENOPROTOOPT; | 711 | return -ENOPROTOOPT; |
@@ -743,45 +723,18 @@ static int setsockopt(struct socket *sock, | |||
743 | release_sock(&cf_sk->sk); | 723 | release_sock(&cf_sk->sk); |
744 | return 0; | 724 | return 0; |
745 | 725 | ||
746 | case SO_PRIORITY: | ||
747 | if (lvl != SOL_SOCKET) | ||
748 | goto bad_sol; | ||
749 | if (ol < sizeof(int)) | ||
750 | return -EINVAL; | ||
751 | if (copy_from_user(&prio, ov, sizeof(int))) | ||
752 | return -EINVAL; | ||
753 | lock_sock(&(cf_sk->sk)); | ||
754 | cf_sk->conn_req.priority = prio; | ||
755 | release_sock(&cf_sk->sk); | ||
756 | return 0; | ||
757 | |||
758 | case SO_BINDTODEVICE: | ||
759 | if (lvl != SOL_SOCKET) | ||
760 | goto bad_sol; | ||
761 | if (ol < sizeof(struct ifreq)) | ||
762 | return -EINVAL; | ||
763 | if (copy_from_user(&ifreq, ov, sizeof(ifreq))) | ||
764 | return -EFAULT; | ||
765 | lock_sock(&(cf_sk->sk)); | ||
766 | strncpy(cf_sk->conn_req.link_name, ifreq.ifr_name, | ||
767 | sizeof(cf_sk->conn_req.link_name)); | ||
768 | cf_sk->conn_req.link_name | ||
769 | [sizeof(cf_sk->conn_req.link_name)-1] = 0; | ||
770 | release_sock(&cf_sk->sk); | ||
771 | return 0; | ||
772 | |||
773 | case CAIFSO_REQ_PARAM: | 726 | case CAIFSO_REQ_PARAM: |
774 | if (lvl != SOL_CAIF) | 727 | if (lvl != SOL_CAIF) |
775 | goto bad_sol; | 728 | goto bad_sol; |
776 | if (cf_sk->sk.sk_protocol != CAIFPROTO_UTIL) | 729 | if (cf_sk->sk.sk_protocol != CAIFPROTO_UTIL) |
777 | return -ENOPROTOOPT; | 730 | return -ENOPROTOOPT; |
778 | lock_sock(&(cf_sk->sk)); | 731 | lock_sock(&(cf_sk->sk)); |
779 | cf_sk->conn_req.param.size = ol; | ||
780 | if (ol > sizeof(cf_sk->conn_req.param.data) || | 732 | if (ol > sizeof(cf_sk->conn_req.param.data) || |
781 | copy_from_user(&cf_sk->conn_req.param.data, ov, ol)) { | 733 | copy_from_user(&cf_sk->conn_req.param.data, ov, ol)) { |
782 | release_sock(&cf_sk->sk); | 734 | release_sock(&cf_sk->sk); |
783 | return -EINVAL; | 735 | return -EINVAL; |
784 | } | 736 | } |
737 | cf_sk->conn_req.param.size = ol; | ||
785 | release_sock(&cf_sk->sk); | 738 | release_sock(&cf_sk->sk); |
786 | return 0; | 739 | return 0; |
787 | 740 | ||
@@ -862,7 +815,8 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, | |||
862 | sk->sk_state == CAIF_DISCONNECTED); | 815 | sk->sk_state == CAIF_DISCONNECTED); |
863 | if (sk->sk_shutdown & SHUTDOWN_MASK) { | 816 | if (sk->sk_shutdown & SHUTDOWN_MASK) { |
864 | /* Allow re-connect after SHUTDOWN_IND */ | 817 | /* Allow re-connect after SHUTDOWN_IND */ |
865 | caif_disconnect_client(&cf_sk->layer); | 818 | caif_disconnect_client(sock_net(sk), &cf_sk->layer); |
819 | caif_free_client(&cf_sk->layer); | ||
866 | break; | 820 | break; |
867 | } | 821 | } |
868 | /* No reconnect on a seqpacket socket */ | 822 | /* No reconnect on a seqpacket socket */ |
@@ -888,10 +842,24 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, | |||
888 | sock->state = SS_CONNECTING; | 842 | sock->state = SS_CONNECTING; |
889 | sk->sk_state = CAIF_CONNECTING; | 843 | sk->sk_state = CAIF_CONNECTING; |
890 | 844 | ||
845 | /* Check priority value comming from socket */ | ||
846 | /* if priority value is out of range it will be ajusted */ | ||
847 | if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX) | ||
848 | cf_sk->conn_req.priority = CAIF_PRIO_MAX; | ||
849 | else if (cf_sk->sk.sk_priority < CAIF_PRIO_MIN) | ||
850 | cf_sk->conn_req.priority = CAIF_PRIO_MIN; | ||
851 | else | ||
852 | cf_sk->conn_req.priority = cf_sk->sk.sk_priority; | ||
853 | |||
854 | /*ifindex = id of the interface.*/ | ||
855 | cf_sk->conn_req.ifindex = cf_sk->sk.sk_bound_dev_if; | ||
856 | |||
891 | dbfs_atomic_inc(&cnt.num_connect_req); | 857 | dbfs_atomic_inc(&cnt.num_connect_req); |
892 | cf_sk->layer.receive = caif_sktrecv_cb; | 858 | cf_sk->layer.receive = caif_sktrecv_cb; |
893 | err = caif_connect_client(&cf_sk->conn_req, | 859 | |
860 | err = caif_connect_client(sock_net(sk), &cf_sk->conn_req, | ||
894 | &cf_sk->layer, &ifindex, &headroom, &tailroom); | 861 | &cf_sk->layer, &ifindex, &headroom, &tailroom); |
862 | |||
895 | if (err < 0) { | 863 | if (err < 0) { |
896 | cf_sk->sk.sk_socket->state = SS_UNCONNECTED; | 864 | cf_sk->sk.sk_socket->state = SS_UNCONNECTED; |
897 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; | 865 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; |
@@ -912,8 +880,8 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, | |||
912 | cf_sk->tailroom = tailroom; | 880 | cf_sk->tailroom = tailroom; |
913 | cf_sk->maxframe = mtu - (headroom + tailroom); | 881 | cf_sk->maxframe = mtu - (headroom + tailroom); |
914 | if (cf_sk->maxframe < 1) { | 882 | if (cf_sk->maxframe < 1) { |
915 | pr_warning("CAIF: %s(): CAIF Interface MTU too small (%u)\n", | 883 | pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu); |
916 | __func__, mtu); | 884 | err = -ENODEV; |
917 | goto out; | 885 | goto out; |
918 | } | 886 | } |
919 | 887 | ||
@@ -959,7 +927,6 @@ static int caif_release(struct socket *sock) | |||
959 | { | 927 | { |
960 | struct sock *sk = sock->sk; | 928 | struct sock *sk = sock->sk; |
961 | struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); | 929 | struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); |
962 | int res = 0; | ||
963 | 930 | ||
964 | if (!sk) | 931 | if (!sk) |
965 | return 0; | 932 | return 0; |
@@ -971,13 +938,14 @@ static int caif_release(struct socket *sock) | |||
971 | * caif_queue_rcv_skb checks SOCK_DEAD holding the queue lock, | 938 | * caif_queue_rcv_skb checks SOCK_DEAD holding the queue lock, |
972 | * this ensures no packets when sock is dead. | 939 | * this ensures no packets when sock is dead. |
973 | */ | 940 | */ |
974 | spin_lock(&sk->sk_receive_queue.lock); | 941 | spin_lock_bh(&sk->sk_receive_queue.lock); |
975 | sock_set_flag(sk, SOCK_DEAD); | 942 | sock_set_flag(sk, SOCK_DEAD); |
976 | spin_unlock(&sk->sk_receive_queue.lock); | 943 | spin_unlock_bh(&sk->sk_receive_queue.lock); |
977 | sock->sk = NULL; | 944 | sock->sk = NULL; |
978 | 945 | ||
979 | dbfs_atomic_inc(&cnt.num_disconnect); | 946 | dbfs_atomic_inc(&cnt.num_disconnect); |
980 | 947 | ||
948 | WARN_ON(IS_ERR(cf_sk->debugfs_socket_dir)); | ||
981 | if (cf_sk->debugfs_socket_dir != NULL) | 949 | if (cf_sk->debugfs_socket_dir != NULL) |
982 | debugfs_remove_recursive(cf_sk->debugfs_socket_dir); | 950 | debugfs_remove_recursive(cf_sk->debugfs_socket_dir); |
983 | 951 | ||
@@ -985,19 +953,15 @@ static int caif_release(struct socket *sock) | |||
985 | sk->sk_state = CAIF_DISCONNECTED; | 953 | sk->sk_state = CAIF_DISCONNECTED; |
986 | sk->sk_shutdown = SHUTDOWN_MASK; | 954 | sk->sk_shutdown = SHUTDOWN_MASK; |
987 | 955 | ||
988 | if (cf_sk->sk.sk_socket->state == SS_CONNECTED || | 956 | caif_disconnect_client(sock_net(sk), &cf_sk->layer); |
989 | cf_sk->sk.sk_socket->state == SS_CONNECTING) | ||
990 | res = caif_disconnect_client(&cf_sk->layer); | ||
991 | |||
992 | cf_sk->sk.sk_socket->state = SS_DISCONNECTING; | 957 | cf_sk->sk.sk_socket->state = SS_DISCONNECTING; |
993 | wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); | 958 | wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); |
994 | 959 | ||
995 | sock_orphan(sk); | 960 | sock_orphan(sk); |
996 | cf_sk->layer.dn = NULL; | ||
997 | sk_stream_kill_queues(&cf_sk->sk); | 961 | sk_stream_kill_queues(&cf_sk->sk); |
998 | release_sock(sk); | 962 | release_sock(sk); |
999 | sock_put(sk); | 963 | sock_put(sk); |
1000 | return res; | 964 | return 0; |
1001 | } | 965 | } |
1002 | 966 | ||
1003 | /* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */ | 967 | /* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */ |
@@ -1084,16 +1048,18 @@ static void caif_sock_destructor(struct sock *sk) | |||
1084 | caif_assert(sk_unhashed(sk)); | 1048 | caif_assert(sk_unhashed(sk)); |
1085 | caif_assert(!sk->sk_socket); | 1049 | caif_assert(!sk->sk_socket); |
1086 | if (!sock_flag(sk, SOCK_DEAD)) { | 1050 | if (!sock_flag(sk, SOCK_DEAD)) { |
1087 | pr_info("Attempt to release alive CAIF socket: %p\n", sk); | 1051 | pr_debug("Attempt to release alive CAIF socket: %p\n", sk); |
1088 | return; | 1052 | return; |
1089 | } | 1053 | } |
1090 | sk_stream_kill_queues(&cf_sk->sk); | 1054 | sk_stream_kill_queues(&cf_sk->sk); |
1091 | dbfs_atomic_dec(&cnt.caif_nr_socks); | 1055 | dbfs_atomic_dec(&cnt.caif_nr_socks); |
1056 | caif_free_client(&cf_sk->layer); | ||
1092 | } | 1057 | } |
1093 | 1058 | ||
1094 | static int caif_create(struct net *net, struct socket *sock, int protocol, | 1059 | static int caif_create(struct net *net, struct socket *sock, int protocol, |
1095 | int kern) | 1060 | int kern) |
1096 | { | 1061 | { |
1062 | int num; | ||
1097 | struct sock *sk = NULL; | 1063 | struct sock *sk = NULL; |
1098 | struct caifsock *cf_sk = NULL; | 1064 | struct caifsock *cf_sk = NULL; |
1099 | static struct proto prot = {.name = "PF_CAIF", | 1065 | static struct proto prot = {.name = "PF_CAIF", |
@@ -1132,10 +1098,6 @@ static int caif_create(struct net *net, struct socket *sock, int protocol, | |||
1132 | /* Store the protocol */ | 1098 | /* Store the protocol */ |
1133 | sk->sk_protocol = (unsigned char) protocol; | 1099 | sk->sk_protocol = (unsigned char) protocol; |
1134 | 1100 | ||
1135 | /* Sendbuf dictates the amount of outbound packets not yet sent */ | ||
1136 | sk->sk_sndbuf = CAIF_DEF_SNDBUF; | ||
1137 | sk->sk_rcvbuf = CAIF_DEF_RCVBUF; | ||
1138 | |||
1139 | /* | 1101 | /* |
1140 | * Lock in order to try to stop someone from opening the socket | 1102 | * Lock in order to try to stop someone from opening the socket |
1141 | * too early. | 1103 | * too early. |
@@ -1155,19 +1117,21 @@ static int caif_create(struct net *net, struct socket *sock, int protocol, | |||
1155 | set_rx_flow_on(cf_sk); | 1117 | set_rx_flow_on(cf_sk); |
1156 | 1118 | ||
1157 | /* Set default options on configuration */ | 1119 | /* Set default options on configuration */ |
1158 | cf_sk->conn_req.priority = CAIF_PRIO_NORMAL; | 1120 | cf_sk->sk.sk_priority = CAIF_PRIO_NORMAL; |
1159 | cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY; | 1121 | cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY; |
1160 | cf_sk->conn_req.protocol = protocol; | 1122 | cf_sk->conn_req.protocol = protocol; |
1161 | /* Increase the number of sockets created. */ | 1123 | /* Increase the number of sockets created. */ |
1162 | dbfs_atomic_inc(&cnt.caif_nr_socks); | 1124 | dbfs_atomic_inc(&cnt.caif_nr_socks); |
1125 | num = dbfs_atomic_inc(&cnt.caif_sock_create); | ||
1163 | #ifdef CONFIG_DEBUG_FS | 1126 | #ifdef CONFIG_DEBUG_FS |
1164 | if (!IS_ERR(debugfsdir)) { | 1127 | if (!IS_ERR(debugfsdir)) { |
1128 | |||
1165 | /* Fill in some information concerning the misc socket. */ | 1129 | /* Fill in some information concerning the misc socket. */ |
1166 | snprintf(cf_sk->name, sizeof(cf_sk->name), "cfsk%d", | 1130 | snprintf(cf_sk->name, sizeof(cf_sk->name), "cfsk%d", num); |
1167 | atomic_read(&cnt.caif_nr_socks)); | ||
1168 | 1131 | ||
1169 | cf_sk->debugfs_socket_dir = | 1132 | cf_sk->debugfs_socket_dir = |
1170 | debugfs_create_dir(cf_sk->name, debugfsdir); | 1133 | debugfs_create_dir(cf_sk->name, debugfsdir); |
1134 | |||
1171 | debugfs_create_u32("sk_state", S_IRUSR | S_IWUSR, | 1135 | debugfs_create_u32("sk_state", S_IRUSR | S_IWUSR, |
1172 | cf_sk->debugfs_socket_dir, | 1136 | cf_sk->debugfs_socket_dir, |
1173 | (u32 *) &cf_sk->sk.sk_state); | 1137 | (u32 *) &cf_sk->sk.sk_state); |
@@ -1211,6 +1175,9 @@ static int __init caif_sktinit_module(void) | |||
1211 | debugfs_create_u32("num_sockets", S_IRUSR | S_IWUSR, | 1175 | debugfs_create_u32("num_sockets", S_IRUSR | S_IWUSR, |
1212 | debugfsdir, | 1176 | debugfsdir, |
1213 | (u32 *) &cnt.caif_nr_socks); | 1177 | (u32 *) &cnt.caif_nr_socks); |
1178 | debugfs_create_u32("num_create", S_IRUSR | S_IWUSR, | ||
1179 | debugfsdir, | ||
1180 | (u32 *) &cnt.caif_sock_create); | ||
1214 | debugfs_create_u32("num_connect_req", S_IRUSR | S_IWUSR, | 1181 | debugfs_create_u32("num_connect_req", S_IRUSR | S_IWUSR, |
1215 | debugfsdir, | 1182 | debugfsdir, |
1216 | (u32 *) &cnt.num_connect_req); | 1183 | (u32 *) &cnt.num_connect_req); |
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 1c29189b344d..52fe33bee029 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c | |||
@@ -3,10 +3,14 @@ | |||
3 | * Author: Sjur Brendeland/sjur.brandeland@stericsson.com | 3 | * Author: Sjur Brendeland/sjur.brandeland@stericsson.com |
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | |||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
6 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
7 | #include <linux/stddef.h> | 10 | #include <linux/stddef.h> |
8 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
9 | #include <linux/netdevice.h> | 12 | #include <linux/netdevice.h> |
13 | #include <linux/module.h> | ||
10 | #include <net/caif/caif_layer.h> | 14 | #include <net/caif/caif_layer.h> |
11 | #include <net/caif/cfpkt.h> | 15 | #include <net/caif/cfpkt.h> |
12 | #include <net/caif/cfcnfg.h> | 16 | #include <net/caif/cfcnfg.h> |
@@ -15,20 +19,17 @@ | |||
15 | #include <net/caif/cffrml.h> | 19 | #include <net/caif/cffrml.h> |
16 | #include <net/caif/cfserl.h> | 20 | #include <net/caif/cfserl.h> |
17 | #include <net/caif/cfsrvl.h> | 21 | #include <net/caif/cfsrvl.h> |
18 | 22 | #include <net/caif/caif_dev.h> | |
19 | #include <linux/module.h> | ||
20 | #include <asm/atomic.h> | ||
21 | |||
22 | #define MAX_PHY_LAYERS 7 | ||
23 | #define PHY_NAME_LEN 20 | ||
24 | 23 | ||
25 | #define container_obj(layr) container_of(layr, struct cfcnfg, layer) | 24 | #define container_obj(layr) container_of(layr, struct cfcnfg, layer) |
26 | #define RFM_FRAGMENT_SIZE 4030 | ||
27 | 25 | ||
28 | /* Information about CAIF physical interfaces held by Config Module in order | 26 | /* Information about CAIF physical interfaces held by Config Module in order |
29 | * to manage physical interfaces | 27 | * to manage physical interfaces |
30 | */ | 28 | */ |
31 | struct cfcnfg_phyinfo { | 29 | struct cfcnfg_phyinfo { |
30 | struct list_head node; | ||
31 | bool up; | ||
32 | |||
32 | /* Pointer to the layer below the MUX (framing layer) */ | 33 | /* Pointer to the layer below the MUX (framing layer) */ |
33 | struct cflayer *frm_layer; | 34 | struct cflayer *frm_layer; |
34 | /* Pointer to the lowest actual physical layer */ | 35 | /* Pointer to the lowest actual physical layer */ |
@@ -38,9 +39,6 @@ struct cfcnfg_phyinfo { | |||
38 | /* Preference of the physical in interface */ | 39 | /* Preference of the physical in interface */ |
39 | enum cfcnfg_phy_preference pref; | 40 | enum cfcnfg_phy_preference pref; |
40 | 41 | ||
41 | /* Reference count, number of channels using the device */ | ||
42 | int phy_ref_count; | ||
43 | |||
44 | /* Information about the physical device */ | 42 | /* Information about the physical device */ |
45 | struct dev_info dev_info; | 43 | struct dev_info dev_info; |
46 | 44 | ||
@@ -58,8 +56,8 @@ struct cfcnfg { | |||
58 | struct cflayer layer; | 56 | struct cflayer layer; |
59 | struct cflayer *ctrl; | 57 | struct cflayer *ctrl; |
60 | struct cflayer *mux; | 58 | struct cflayer *mux; |
61 | u8 last_phyid; | 59 | struct list_head phys; |
62 | struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS]; | 60 | struct mutex lock; |
63 | }; | 61 | }; |
64 | 62 | ||
65 | static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, | 63 | static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, |
@@ -75,10 +73,13 @@ struct cfcnfg *cfcnfg_create(void) | |||
75 | { | 73 | { |
76 | struct cfcnfg *this; | 74 | struct cfcnfg *this; |
77 | struct cfctrl_rsp *resp; | 75 | struct cfctrl_rsp *resp; |
76 | |||
77 | might_sleep(); | ||
78 | |||
78 | /* Initiate this layer */ | 79 | /* Initiate this layer */ |
79 | this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC); | 80 | this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC); |
80 | if (!this) { | 81 | if (!this) { |
81 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 82 | pr_warn("Out of memory\n"); |
82 | return NULL; | 83 | return NULL; |
83 | } | 84 | } |
84 | this->mux = cfmuxl_create(); | 85 | this->mux = cfmuxl_create(); |
@@ -98,27 +99,33 @@ struct cfcnfg *cfcnfg_create(void) | |||
98 | resp->radioset_rsp = cfctrl_resp_func; | 99 | resp->radioset_rsp = cfctrl_resp_func; |
99 | resp->linksetup_rsp = cfcnfg_linkup_rsp; | 100 | resp->linksetup_rsp = cfcnfg_linkup_rsp; |
100 | resp->reject_rsp = cfcnfg_reject_rsp; | 101 | resp->reject_rsp = cfcnfg_reject_rsp; |
101 | 102 | INIT_LIST_HEAD(&this->phys); | |
102 | this->last_phyid = 1; | ||
103 | 103 | ||
104 | cfmuxl_set_uplayer(this->mux, this->ctrl, 0); | 104 | cfmuxl_set_uplayer(this->mux, this->ctrl, 0); |
105 | layer_set_dn(this->ctrl, this->mux); | 105 | layer_set_dn(this->ctrl, this->mux); |
106 | layer_set_up(this->ctrl, this); | 106 | layer_set_up(this->ctrl, this); |
107 | mutex_init(&this->lock); | ||
108 | |||
107 | return this; | 109 | return this; |
108 | out_of_mem: | 110 | out_of_mem: |
109 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 111 | pr_warn("Out of memory\n"); |
112 | |||
113 | synchronize_rcu(); | ||
114 | |||
110 | kfree(this->mux); | 115 | kfree(this->mux); |
111 | kfree(this->ctrl); | 116 | kfree(this->ctrl); |
112 | kfree(this); | 117 | kfree(this); |
113 | return NULL; | 118 | return NULL; |
114 | } | 119 | } |
115 | EXPORT_SYMBOL(cfcnfg_create); | ||
116 | 120 | ||
117 | void cfcnfg_remove(struct cfcnfg *cfg) | 121 | void cfcnfg_remove(struct cfcnfg *cfg) |
118 | { | 122 | { |
123 | might_sleep(); | ||
119 | if (cfg) { | 124 | if (cfg) { |
125 | synchronize_rcu(); | ||
126 | |||
120 | kfree(cfg->mux); | 127 | kfree(cfg->mux); |
121 | kfree(cfg->ctrl); | 128 | cfctrl_remove(cfg->ctrl); |
122 | kfree(cfg); | 129 | kfree(cfg); |
123 | } | 130 | } |
124 | } | 131 | } |
@@ -127,139 +134,83 @@ static void cfctrl_resp_func(void) | |||
127 | { | 134 | { |
128 | } | 135 | } |
129 | 136 | ||
137 | static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg, | ||
138 | u8 phyid) | ||
139 | { | ||
140 | struct cfcnfg_phyinfo *phy; | ||
141 | |||
142 | list_for_each_entry_rcu(phy, &cnfg->phys, node) | ||
143 | if (phy->id == phyid) | ||
144 | return phy; | ||
145 | return NULL; | ||
146 | } | ||
147 | |||
130 | static void cfctrl_enum_resp(void) | 148 | static void cfctrl_enum_resp(void) |
131 | { | 149 | { |
132 | } | 150 | } |
133 | 151 | ||
134 | struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, | 152 | static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, |
135 | enum cfcnfg_phy_preference phy_pref) | 153 | enum cfcnfg_phy_preference phy_pref) |
136 | { | 154 | { |
137 | u16 i; | ||
138 | |||
139 | /* Try to match with specified preference */ | 155 | /* Try to match with specified preference */ |
140 | for (i = 1; i < MAX_PHY_LAYERS; i++) { | 156 | struct cfcnfg_phyinfo *phy; |
141 | if (cnfg->phy_layers[i].id == i && | 157 | |
142 | cnfg->phy_layers[i].pref == phy_pref && | 158 | list_for_each_entry_rcu(phy, &cnfg->phys, node) { |
143 | cnfg->phy_layers[i].frm_layer != NULL) { | 159 | if (phy->up && phy->pref == phy_pref && |
144 | caif_assert(cnfg->phy_layers != NULL); | 160 | phy->frm_layer != NULL) |
145 | caif_assert(cnfg->phy_layers[i].id == i); | 161 | |
146 | return &cnfg->phy_layers[i].dev_info; | 162 | return &phy->dev_info; |
147 | } | ||
148 | } | ||
149 | /* Otherwise just return something */ | ||
150 | for (i = 1; i < MAX_PHY_LAYERS; i++) { | ||
151 | if (cnfg->phy_layers[i].id == i) { | ||
152 | caif_assert(cnfg->phy_layers != NULL); | ||
153 | caif_assert(cnfg->phy_layers[i].id == i); | ||
154 | return &cnfg->phy_layers[i].dev_info; | ||
155 | } | ||
156 | } | 163 | } |
157 | 164 | ||
158 | return NULL; | 165 | /* Otherwise just return something */ |
159 | } | 166 | list_for_each_entry_rcu(phy, &cnfg->phys, node) |
167 | if (phy->up) | ||
168 | return &phy->dev_info; | ||
160 | 169 | ||
161 | static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg, | ||
162 | u8 phyid) | ||
163 | { | ||
164 | int i; | ||
165 | /* Try to match with specified preference */ | ||
166 | for (i = 0; i < MAX_PHY_LAYERS; i++) | ||
167 | if (cnfg->phy_layers[i].frm_layer != NULL && | ||
168 | cnfg->phy_layers[i].id == phyid) | ||
169 | return &cnfg->phy_layers[i]; | ||
170 | return NULL; | 170 | return NULL; |
171 | } | 171 | } |
172 | 172 | ||
173 | int cfcnfg_get_named(struct cfcnfg *cnfg, char *name) | 173 | static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) |
174 | { | 174 | { |
175 | int i; | 175 | struct cfcnfg_phyinfo *phy; |
176 | 176 | ||
177 | /* Try to match with specified name */ | 177 | list_for_each_entry_rcu(phy, &cnfg->phys, node) |
178 | for (i = 0; i < MAX_PHY_LAYERS; i++) { | 178 | if (phy->ifindex == ifi && phy->up) |
179 | if (cnfg->phy_layers[i].frm_layer != NULL | 179 | return phy->id; |
180 | && strcmp(cnfg->phy_layers[i].phy_layer->name, | 180 | return -ENODEV; |
181 | name) == 0) | ||
182 | return cnfg->phy_layers[i].frm_layer->id; | ||
183 | } | ||
184 | return 0; | ||
185 | } | 181 | } |
186 | 182 | ||
187 | int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer) | 183 | int caif_disconnect_client(struct net *net, struct cflayer *adap_layer) |
188 | { | 184 | { |
189 | u8 channel_id = 0; | 185 | u8 channel_id; |
190 | int ret = 0; | 186 | struct cfcnfg *cfg = get_cfcnfg(net); |
191 | struct cflayer *servl = NULL; | 187 | |
192 | struct cfcnfg_phyinfo *phyinfo = NULL; | ||
193 | u8 phyid = 0; | ||
194 | caif_assert(adap_layer != NULL); | 188 | caif_assert(adap_layer != NULL); |
189 | cfctrl_cancel_req(cfg->ctrl, adap_layer); | ||
195 | channel_id = adap_layer->id; | 190 | channel_id = adap_layer->id; |
196 | if (adap_layer->dn == NULL || channel_id == 0) { | 191 | if (channel_id != 0) { |
197 | pr_err("CAIF: %s():adap_layer->id is 0\n", __func__); | 192 | struct cflayer *servl; |
198 | ret = -ENOTCONN; | 193 | servl = cfmuxl_remove_uplayer(cfg->mux, channel_id); |
199 | goto end; | 194 | if (servl != NULL) |
200 | } | 195 | layer_set_up(servl, NULL); |
201 | servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id); | 196 | } else |
202 | if (servl == NULL) | 197 | pr_debug("nothing to disconnect\n"); |
203 | goto end; | 198 | cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer); |
204 | layer_set_up(servl, NULL); | 199 | |
205 | ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer); | 200 | /* Do RCU sync before initiating cleanup */ |
206 | if (servl == NULL) { | 201 | synchronize_rcu(); |
207 | pr_err("CAIF: %s(): PROTOCOL ERROR " | ||
208 | "- Error removing service_layer Channel_Id(%d)", | ||
209 | __func__, channel_id); | ||
210 | ret = -EINVAL; | ||
211 | goto end; | ||
212 | } | ||
213 | caif_assert(channel_id == servl->id); | ||
214 | if (adap_layer->dn != NULL) { | ||
215 | phyid = cfsrvl_getphyid(adap_layer->dn); | ||
216 | |||
217 | phyinfo = cfcnfg_get_phyinfo(cnfg, phyid); | ||
218 | if (phyinfo == NULL) { | ||
219 | pr_warning("CAIF: %s(): " | ||
220 | "No interface to send disconnect to\n", | ||
221 | __func__); | ||
222 | ret = -ENODEV; | ||
223 | goto end; | ||
224 | } | ||
225 | if (phyinfo->id != phyid || | ||
226 | phyinfo->phy_layer->id != phyid || | ||
227 | phyinfo->frm_layer->id != phyid) { | ||
228 | pr_err("CAIF: %s(): " | ||
229 | "Inconsistency in phy registration\n", | ||
230 | __func__); | ||
231 | ret = -EINVAL; | ||
232 | goto end; | ||
233 | } | ||
234 | } | ||
235 | if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 && | ||
236 | phyinfo->phy_layer != NULL && | ||
237 | phyinfo->phy_layer->modemcmd != NULL) { | ||
238 | phyinfo->phy_layer->modemcmd(phyinfo->phy_layer, | ||
239 | _CAIF_MODEMCMD_PHYIF_USELESS); | ||
240 | } | ||
241 | end: | ||
242 | cfsrvl_put(servl); | ||
243 | cfctrl_cancel_req(cnfg->ctrl, adap_layer); | ||
244 | if (adap_layer->ctrlcmd != NULL) | 202 | if (adap_layer->ctrlcmd != NULL) |
245 | adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0); | 203 | adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0); |
246 | return ret; | 204 | return 0; |
247 | |||
248 | } | ||
249 | EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer); | ||
250 | 205 | ||
251 | void cfcnfg_release_adap_layer(struct cflayer *adap_layer) | ||
252 | { | ||
253 | if (adap_layer->dn) | ||
254 | cfsrvl_put(adap_layer->dn); | ||
255 | } | 206 | } |
256 | EXPORT_SYMBOL(cfcnfg_release_adap_layer); | 207 | EXPORT_SYMBOL(caif_disconnect_client); |
257 | 208 | ||
258 | static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) | 209 | static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) |
259 | { | 210 | { |
260 | } | 211 | } |
261 | 212 | ||
262 | int protohead[CFCTRL_SRV_MASK] = { | 213 | static const int protohead[CFCTRL_SRV_MASK] = { |
263 | [CFCTRL_SRV_VEI] = 4, | 214 | [CFCTRL_SRV_VEI] = 4, |
264 | [CFCTRL_SRV_DATAGRAM] = 7, | 215 | [CFCTRL_SRV_DATAGRAM] = 7, |
265 | [CFCTRL_SRV_UTIL] = 4, | 216 | [CFCTRL_SRV_UTIL] = 4, |
@@ -267,50 +218,157 @@ int protohead[CFCTRL_SRV_MASK] = { | |||
267 | [CFCTRL_SRV_DBG] = 3, | 218 | [CFCTRL_SRV_DBG] = 3, |
268 | }; | 219 | }; |
269 | 220 | ||
270 | int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, | 221 | |
271 | struct cfctrl_link_param *param, | 222 | static int caif_connect_req_to_link_param(struct cfcnfg *cnfg, |
272 | struct cflayer *adap_layer, | 223 | struct caif_connect_request *s, |
273 | int *ifindex, | 224 | struct cfctrl_link_param *l) |
225 | { | ||
226 | struct dev_info *dev_info; | ||
227 | enum cfcnfg_phy_preference pref; | ||
228 | int res; | ||
229 | |||
230 | memset(l, 0, sizeof(*l)); | ||
231 | /* In caif protocol low value is high priority */ | ||
232 | l->priority = CAIF_PRIO_MAX - s->priority + 1; | ||
233 | |||
234 | if (s->ifindex != 0) { | ||
235 | res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex); | ||
236 | if (res < 0) | ||
237 | return res; | ||
238 | l->phyid = res; | ||
239 | } else { | ||
240 | switch (s->link_selector) { | ||
241 | case CAIF_LINK_HIGH_BANDW: | ||
242 | pref = CFPHYPREF_HIGH_BW; | ||
243 | break; | ||
244 | case CAIF_LINK_LOW_LATENCY: | ||
245 | pref = CFPHYPREF_LOW_LAT; | ||
246 | break; | ||
247 | default: | ||
248 | return -EINVAL; | ||
249 | } | ||
250 | dev_info = cfcnfg_get_phyid(cnfg, pref); | ||
251 | if (dev_info == NULL) | ||
252 | return -ENODEV; | ||
253 | l->phyid = dev_info->id; | ||
254 | } | ||
255 | switch (s->protocol) { | ||
256 | case CAIFPROTO_AT: | ||
257 | l->linktype = CFCTRL_SRV_VEI; | ||
258 | l->endpoint = (s->sockaddr.u.at.type >> 2) & 0x3; | ||
259 | l->chtype = s->sockaddr.u.at.type & 0x3; | ||
260 | break; | ||
261 | case CAIFPROTO_DATAGRAM: | ||
262 | l->linktype = CFCTRL_SRV_DATAGRAM; | ||
263 | l->chtype = 0x00; | ||
264 | l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; | ||
265 | break; | ||
266 | case CAIFPROTO_DATAGRAM_LOOP: | ||
267 | l->linktype = CFCTRL_SRV_DATAGRAM; | ||
268 | l->chtype = 0x03; | ||
269 | l->endpoint = 0x00; | ||
270 | l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; | ||
271 | break; | ||
272 | case CAIFPROTO_RFM: | ||
273 | l->linktype = CFCTRL_SRV_RFM; | ||
274 | l->u.datagram.connid = s->sockaddr.u.rfm.connection_id; | ||
275 | strncpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume, | ||
276 | sizeof(l->u.rfm.volume)-1); | ||
277 | l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0; | ||
278 | break; | ||
279 | case CAIFPROTO_UTIL: | ||
280 | l->linktype = CFCTRL_SRV_UTIL; | ||
281 | l->endpoint = 0x00; | ||
282 | l->chtype = 0x00; | ||
283 | strncpy(l->u.utility.name, s->sockaddr.u.util.service, | ||
284 | sizeof(l->u.utility.name)-1); | ||
285 | l->u.utility.name[sizeof(l->u.utility.name)-1] = 0; | ||
286 | caif_assert(sizeof(l->u.utility.name) > 10); | ||
287 | l->u.utility.paramlen = s->param.size; | ||
288 | if (l->u.utility.paramlen > sizeof(l->u.utility.params)) | ||
289 | l->u.utility.paramlen = sizeof(l->u.utility.params); | ||
290 | |||
291 | memcpy(l->u.utility.params, s->param.data, | ||
292 | l->u.utility.paramlen); | ||
293 | |||
294 | break; | ||
295 | case CAIFPROTO_DEBUG: | ||
296 | l->linktype = CFCTRL_SRV_DBG; | ||
297 | l->endpoint = s->sockaddr.u.dbg.service; | ||
298 | l->chtype = s->sockaddr.u.dbg.type; | ||
299 | break; | ||
300 | default: | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | int caif_connect_client(struct net *net, struct caif_connect_request *conn_req, | ||
307 | struct cflayer *adap_layer, int *ifindex, | ||
274 | int *proto_head, | 308 | int *proto_head, |
275 | int *proto_tail) | 309 | int *proto_tail) |
276 | { | 310 | { |
277 | struct cflayer *frml; | 311 | struct cflayer *frml; |
312 | struct cfcnfg_phyinfo *phy; | ||
313 | int err; | ||
314 | struct cfctrl_link_param param; | ||
315 | struct cfcnfg *cfg = get_cfcnfg(net); | ||
316 | caif_assert(cfg != NULL); | ||
317 | |||
318 | rcu_read_lock(); | ||
319 | err = caif_connect_req_to_link_param(cfg, conn_req, ¶m); | ||
320 | if (err) | ||
321 | goto unlock; | ||
322 | |||
323 | phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid); | ||
324 | if (!phy) { | ||
325 | err = -ENODEV; | ||
326 | goto unlock; | ||
327 | } | ||
328 | err = -EINVAL; | ||
329 | |||
278 | if (adap_layer == NULL) { | 330 | if (adap_layer == NULL) { |
279 | pr_err("CAIF: %s(): adap_layer is zero", __func__); | 331 | pr_err("adap_layer is zero\n"); |
280 | return -EINVAL; | 332 | goto unlock; |
281 | } | 333 | } |
282 | if (adap_layer->receive == NULL) { | 334 | if (adap_layer->receive == NULL) { |
283 | pr_err("CAIF: %s(): adap_layer->receive is NULL", __func__); | 335 | pr_err("adap_layer->receive is NULL\n"); |
284 | return -EINVAL; | 336 | goto unlock; |
285 | } | 337 | } |
286 | if (adap_layer->ctrlcmd == NULL) { | 338 | if (adap_layer->ctrlcmd == NULL) { |
287 | pr_err("CAIF: %s(): adap_layer->ctrlcmd == NULL", __func__); | 339 | pr_err("adap_layer->ctrlcmd == NULL\n"); |
288 | return -EINVAL; | 340 | goto unlock; |
289 | } | 341 | } |
290 | frml = cnfg->phy_layers[param->phyid].frm_layer; | 342 | |
343 | err = -ENODEV; | ||
344 | frml = phy->frm_layer; | ||
291 | if (frml == NULL) { | 345 | if (frml == NULL) { |
292 | pr_err("CAIF: %s(): Specified PHY type does not exist!", | 346 | pr_err("Specified PHY type does not exist!\n"); |
293 | __func__); | 347 | goto unlock; |
294 | return -ENODEV; | ||
295 | } | 348 | } |
296 | caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id); | 349 | caif_assert(param.phyid == phy->id); |
297 | caif_assert(cnfg->phy_layers[param->phyid].frm_layer->id == | 350 | caif_assert(phy->frm_layer->id == |
298 | param->phyid); | 351 | param.phyid); |
299 | caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id == | 352 | caif_assert(phy->phy_layer->id == |
300 | param->phyid); | 353 | param.phyid); |
301 | 354 | ||
302 | *ifindex = cnfg->phy_layers[param->phyid].ifindex; | 355 | *ifindex = phy->ifindex; |
356 | *proto_tail = 2; | ||
303 | *proto_head = | 357 | *proto_head = |
304 | protohead[param->linktype]+ | ||
305 | (cnfg->phy_layers[param->phyid].use_stx ? 1 : 0); | ||
306 | 358 | ||
307 | *proto_tail = 2; | 359 | protohead[param.linktype] + (phy->use_stx ? 1 : 0); |
360 | |||
361 | rcu_read_unlock(); | ||
308 | 362 | ||
309 | /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ | 363 | /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ |
310 | cfctrl_enum_req(cnfg->ctrl, param->phyid); | 364 | cfctrl_enum_req(cfg->ctrl, param.phyid); |
311 | return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer); | 365 | return cfctrl_linkup_request(cfg->ctrl, ¶m, adap_layer); |
366 | |||
367 | unlock: | ||
368 | rcu_read_unlock(); | ||
369 | return err; | ||
312 | } | 370 | } |
313 | EXPORT_SYMBOL(cfcnfg_add_adaptation_layer); | 371 | EXPORT_SYMBOL(caif_connect_client); |
314 | 372 | ||
315 | static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, | 373 | static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, |
316 | struct cflayer *adapt_layer) | 374 | struct cflayer *adapt_layer) |
@@ -322,34 +380,45 @@ static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, | |||
322 | 380 | ||
323 | static void | 381 | static void |
324 | cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, | 382 | cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, |
325 | u8 phyid, struct cflayer *adapt_layer) | 383 | u8 phyid, struct cflayer *adapt_layer) |
326 | { | 384 | { |
327 | struct cfcnfg *cnfg = container_obj(layer); | 385 | struct cfcnfg *cnfg = container_obj(layer); |
328 | struct cflayer *servicel = NULL; | 386 | struct cflayer *servicel = NULL; |
329 | struct cfcnfg_phyinfo *phyinfo; | 387 | struct cfcnfg_phyinfo *phyinfo; |
330 | struct net_device *netdev; | 388 | struct net_device *netdev; |
331 | 389 | ||
390 | if (channel_id == 0) { | ||
391 | pr_warn("received channel_id zero\n"); | ||
392 | if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL) | ||
393 | adapt_layer->ctrlcmd(adapt_layer, | ||
394 | CAIF_CTRLCMD_INIT_FAIL_RSP, 0); | ||
395 | return; | ||
396 | } | ||
397 | |||
398 | rcu_read_lock(); | ||
399 | |||
332 | if (adapt_layer == NULL) { | 400 | if (adapt_layer == NULL) { |
333 | pr_debug("CAIF: %s(): link setup response " | 401 | pr_debug("link setup response but no client exist," |
334 | "but no client exist, send linkdown back\n", | 402 | "send linkdown back\n"); |
335 | __func__); | ||
336 | cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL); | 403 | cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL); |
337 | return; | 404 | goto unlock; |
338 | } | 405 | } |
339 | 406 | ||
340 | caif_assert(cnfg != NULL); | 407 | caif_assert(cnfg != NULL); |
341 | caif_assert(phyid != 0); | 408 | caif_assert(phyid != 0); |
342 | phyinfo = &cnfg->phy_layers[phyid]; | 409 | |
410 | phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); | ||
411 | if (phyinfo == NULL) { | ||
412 | pr_err("ERROR: Link Layer Device dissapeared" | ||
413 | "while connecting\n"); | ||
414 | goto unlock; | ||
415 | } | ||
416 | |||
417 | caif_assert(phyinfo != NULL); | ||
343 | caif_assert(phyinfo->id == phyid); | 418 | caif_assert(phyinfo->id == phyid); |
344 | caif_assert(phyinfo->phy_layer != NULL); | 419 | caif_assert(phyinfo->phy_layer != NULL); |
345 | caif_assert(phyinfo->phy_layer->id == phyid); | 420 | caif_assert(phyinfo->phy_layer->id == phyid); |
346 | 421 | ||
347 | phyinfo->phy_ref_count++; | ||
348 | if (phyinfo->phy_ref_count == 1 && | ||
349 | phyinfo->phy_layer->modemcmd != NULL) { | ||
350 | phyinfo->phy_layer->modemcmd(phyinfo->phy_layer, | ||
351 | _CAIF_MODEMCMD_PHYIF_USEFULL); | ||
352 | } | ||
353 | adapt_layer->id = channel_id; | 422 | adapt_layer->id = channel_id; |
354 | 423 | ||
355 | switch (serv) { | 424 | switch (serv) { |
@@ -357,7 +426,8 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, | |||
357 | servicel = cfvei_create(channel_id, &phyinfo->dev_info); | 426 | servicel = cfvei_create(channel_id, &phyinfo->dev_info); |
358 | break; | 427 | break; |
359 | case CFCTRL_SRV_DATAGRAM: | 428 | case CFCTRL_SRV_DATAGRAM: |
360 | servicel = cfdgml_create(channel_id, &phyinfo->dev_info); | 429 | servicel = cfdgml_create(channel_id, |
430 | &phyinfo->dev_info); | ||
361 | break; | 431 | break; |
362 | case CFCTRL_SRV_RFM: | 432 | case CFCTRL_SRV_RFM: |
363 | netdev = phyinfo->dev_info.dev; | 433 | netdev = phyinfo->dev_info.dev; |
@@ -374,96 +444,92 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, | |||
374 | servicel = cfdbgl_create(channel_id, &phyinfo->dev_info); | 444 | servicel = cfdbgl_create(channel_id, &phyinfo->dev_info); |
375 | break; | 445 | break; |
376 | default: | 446 | default: |
377 | pr_err("CAIF: %s(): Protocol error. " | 447 | pr_err("Protocol error. Link setup response " |
378 | "Link setup response - unknown channel type\n", | 448 | "- unknown channel type\n"); |
379 | __func__); | 449 | goto unlock; |
380 | return; | ||
381 | } | 450 | } |
382 | if (!servicel) { | 451 | if (!servicel) { |
383 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 452 | pr_warn("Out of memory\n"); |
384 | return; | 453 | goto unlock; |
385 | } | 454 | } |
386 | layer_set_dn(servicel, cnfg->mux); | 455 | layer_set_dn(servicel, cnfg->mux); |
387 | cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id); | 456 | cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id); |
388 | layer_set_up(servicel, adapt_layer); | 457 | layer_set_up(servicel, adapt_layer); |
389 | layer_set_dn(adapt_layer, servicel); | 458 | layer_set_dn(adapt_layer, servicel); |
390 | cfsrvl_get(servicel); | 459 | |
460 | rcu_read_unlock(); | ||
461 | |||
391 | servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0); | 462 | servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0); |
463 | return; | ||
464 | unlock: | ||
465 | rcu_read_unlock(); | ||
392 | } | 466 | } |
393 | 467 | ||
394 | void | 468 | void |
395 | cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, | 469 | cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, |
396 | struct net_device *dev, struct cflayer *phy_layer, | 470 | struct net_device *dev, struct cflayer *phy_layer, |
397 | u16 *phyid, enum cfcnfg_phy_preference pref, | 471 | enum cfcnfg_phy_preference pref, |
398 | bool fcs, bool stx) | 472 | bool fcs, bool stx) |
399 | { | 473 | { |
400 | struct cflayer *frml; | 474 | struct cflayer *frml; |
401 | struct cflayer *phy_driver = NULL; | 475 | struct cflayer *phy_driver = NULL; |
476 | struct cfcnfg_phyinfo *phyinfo; | ||
402 | int i; | 477 | int i; |
478 | u8 phyid; | ||
403 | 479 | ||
480 | mutex_lock(&cnfg->lock); | ||
404 | 481 | ||
405 | if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) { | 482 | /* CAIF protocol allow maximum 6 link-layers */ |
406 | *phyid = cnfg->last_phyid; | 483 | for (i = 0; i < 7; i++) { |
407 | 484 | phyid = (dev->ifindex + i) & 0x7; | |
408 | /* range: * 1..(MAX_PHY_LAYERS-1) */ | 485 | if (phyid == 0) |
409 | cnfg->last_phyid = | 486 | continue; |
410 | (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1; | 487 | if (cfcnfg_get_phyinfo_rcu(cnfg, phyid) == NULL) |
411 | } else { | 488 | goto got_phyid; |
412 | *phyid = 0; | ||
413 | for (i = 1; i < MAX_PHY_LAYERS; i++) { | ||
414 | if (cnfg->phy_layers[i].frm_layer == NULL) { | ||
415 | *phyid = i; | ||
416 | break; | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | if (*phyid == 0) { | ||
421 | pr_err("CAIF: %s(): No Available PHY ID\n", __func__); | ||
422 | return; | ||
423 | } | 489 | } |
490 | pr_warn("Too many CAIF Link Layers (max 6)\n"); | ||
491 | goto out; | ||
492 | |||
493 | got_phyid: | ||
494 | phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC); | ||
424 | 495 | ||
425 | switch (phy_type) { | 496 | switch (phy_type) { |
426 | case CFPHYTYPE_FRAG: | 497 | case CFPHYTYPE_FRAG: |
427 | phy_driver = | 498 | phy_driver = |
428 | cfserl_create(CFPHYTYPE_FRAG, *phyid, stx); | 499 | cfserl_create(CFPHYTYPE_FRAG, phyid, stx); |
429 | if (!phy_driver) { | 500 | if (!phy_driver) { |
430 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 501 | pr_warn("Out of memory\n"); |
431 | return; | 502 | goto out; |
432 | } | 503 | } |
433 | |||
434 | break; | 504 | break; |
435 | case CFPHYTYPE_CAIF: | 505 | case CFPHYTYPE_CAIF: |
436 | phy_driver = NULL; | 506 | phy_driver = NULL; |
437 | break; | 507 | break; |
438 | default: | 508 | default: |
439 | pr_err("CAIF: %s(): %d", __func__, phy_type); | 509 | goto out; |
440 | return; | ||
441 | break; | ||
442 | } | 510 | } |
511 | phy_layer->id = phyid; | ||
512 | phyinfo->pref = pref; | ||
513 | phyinfo->id = phyid; | ||
514 | phyinfo->dev_info.id = phyid; | ||
515 | phyinfo->dev_info.dev = dev; | ||
516 | phyinfo->phy_layer = phy_layer; | ||
517 | phyinfo->ifindex = dev->ifindex; | ||
518 | phyinfo->use_stx = stx; | ||
519 | phyinfo->use_fcs = fcs; | ||
520 | |||
521 | frml = cffrml_create(phyid, fcs); | ||
443 | 522 | ||
444 | phy_layer->id = *phyid; | ||
445 | cnfg->phy_layers[*phyid].pref = pref; | ||
446 | cnfg->phy_layers[*phyid].id = *phyid; | ||
447 | cnfg->phy_layers[*phyid].dev_info.id = *phyid; | ||
448 | cnfg->phy_layers[*phyid].dev_info.dev = dev; | ||
449 | cnfg->phy_layers[*phyid].phy_layer = phy_layer; | ||
450 | cnfg->phy_layers[*phyid].phy_ref_count = 0; | ||
451 | cnfg->phy_layers[*phyid].ifindex = dev->ifindex; | ||
452 | cnfg->phy_layers[*phyid].use_stx = stx; | ||
453 | cnfg->phy_layers[*phyid].use_fcs = fcs; | ||
454 | |||
455 | phy_layer->type = phy_type; | ||
456 | frml = cffrml_create(*phyid, fcs); | ||
457 | if (!frml) { | 523 | if (!frml) { |
458 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 524 | pr_warn("Out of memory\n"); |
459 | return; | 525 | kfree(phyinfo); |
526 | goto out; | ||
460 | } | 527 | } |
461 | cnfg->phy_layers[*phyid].frm_layer = frml; | 528 | phyinfo->frm_layer = frml; |
462 | cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid); | ||
463 | layer_set_up(frml, cnfg->mux); | 529 | layer_set_up(frml, cnfg->mux); |
464 | 530 | ||
465 | if (phy_driver != NULL) { | 531 | if (phy_driver != NULL) { |
466 | phy_driver->id = *phyid; | 532 | phy_driver->id = phyid; |
467 | layer_set_dn(frml, phy_driver); | 533 | layer_set_dn(frml, phy_driver); |
468 | layer_set_up(phy_driver, frml); | 534 | layer_set_up(phy_driver, frml); |
469 | layer_set_dn(phy_driver, phy_layer); | 535 | layer_set_dn(phy_driver, phy_layer); |
@@ -472,33 +538,95 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, | |||
472 | layer_set_dn(frml, phy_layer); | 538 | layer_set_dn(frml, phy_layer); |
473 | layer_set_up(phy_layer, frml); | 539 | layer_set_up(phy_layer, frml); |
474 | } | 540 | } |
541 | |||
542 | list_add_rcu(&phyinfo->node, &cnfg->phys); | ||
543 | out: | ||
544 | mutex_unlock(&cnfg->lock); | ||
475 | } | 545 | } |
476 | EXPORT_SYMBOL(cfcnfg_add_phy_layer); | 546 | EXPORT_SYMBOL(cfcnfg_add_phy_layer); |
477 | 547 | ||
548 | int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer, | ||
549 | bool up) | ||
550 | { | ||
551 | struct cfcnfg_phyinfo *phyinfo; | ||
552 | |||
553 | rcu_read_lock(); | ||
554 | phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phy_layer->id); | ||
555 | if (phyinfo == NULL) { | ||
556 | rcu_read_unlock(); | ||
557 | return -ENODEV; | ||
558 | } | ||
559 | |||
560 | if (phyinfo->up == up) { | ||
561 | rcu_read_unlock(); | ||
562 | return 0; | ||
563 | } | ||
564 | phyinfo->up = up; | ||
565 | |||
566 | if (up) { | ||
567 | cffrml_hold(phyinfo->frm_layer); | ||
568 | cfmuxl_set_dnlayer(cnfg->mux, phyinfo->frm_layer, | ||
569 | phy_layer->id); | ||
570 | } else { | ||
571 | cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id); | ||
572 | cffrml_put(phyinfo->frm_layer); | ||
573 | } | ||
574 | |||
575 | rcu_read_unlock(); | ||
576 | return 0; | ||
577 | } | ||
578 | EXPORT_SYMBOL(cfcnfg_set_phy_state); | ||
579 | |||
478 | int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) | 580 | int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) |
479 | { | 581 | { |
480 | struct cflayer *frml, *frml_dn; | 582 | struct cflayer *frml, *frml_dn; |
481 | u16 phyid; | 583 | u16 phyid; |
584 | struct cfcnfg_phyinfo *phyinfo; | ||
585 | |||
586 | might_sleep(); | ||
587 | |||
588 | mutex_lock(&cnfg->lock); | ||
589 | |||
482 | phyid = phy_layer->id; | 590 | phyid = phy_layer->id; |
483 | caif_assert(phyid == cnfg->phy_layers[phyid].id); | 591 | phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); |
484 | caif_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer); | 592 | |
593 | if (phyinfo == NULL) { | ||
594 | mutex_unlock(&cnfg->lock); | ||
595 | return 0; | ||
596 | } | ||
597 | caif_assert(phyid == phyinfo->id); | ||
598 | caif_assert(phy_layer == phyinfo->phy_layer); | ||
485 | caif_assert(phy_layer->id == phyid); | 599 | caif_assert(phy_layer->id == phyid); |
486 | caif_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid); | 600 | caif_assert(phyinfo->frm_layer->id == phyid); |
601 | |||
602 | list_del_rcu(&phyinfo->node); | ||
603 | synchronize_rcu(); | ||
487 | 604 | ||
488 | memset(&cnfg->phy_layers[phy_layer->id], 0, | 605 | /* Fail if reference count is not zero */ |
489 | sizeof(struct cfcnfg_phyinfo)); | 606 | if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) { |
490 | frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id); | 607 | pr_info("Wait for device inuse\n"); |
608 | list_add_rcu(&phyinfo->node, &cnfg->phys); | ||
609 | mutex_unlock(&cnfg->lock); | ||
610 | return -EAGAIN; | ||
611 | } | ||
612 | |||
613 | frml = phyinfo->frm_layer; | ||
491 | frml_dn = frml->dn; | 614 | frml_dn = frml->dn; |
492 | cffrml_set_uplayer(frml, NULL); | 615 | cffrml_set_uplayer(frml, NULL); |
493 | cffrml_set_dnlayer(frml, NULL); | 616 | cffrml_set_dnlayer(frml, NULL); |
494 | kfree(frml); | ||
495 | |||
496 | if (phy_layer != frml_dn) { | 617 | if (phy_layer != frml_dn) { |
497 | layer_set_up(frml_dn, NULL); | 618 | layer_set_up(frml_dn, NULL); |
498 | layer_set_dn(frml_dn, NULL); | 619 | layer_set_dn(frml_dn, NULL); |
499 | kfree(frml_dn); | ||
500 | } | 620 | } |
501 | layer_set_up(phy_layer, NULL); | 621 | layer_set_up(phy_layer, NULL); |
622 | |||
623 | if (phyinfo->phy_layer != frml_dn) | ||
624 | kfree(frml_dn); | ||
625 | |||
626 | cffrml_free(frml); | ||
627 | kfree(phyinfo); | ||
628 | mutex_unlock(&cnfg->lock); | ||
629 | |||
502 | return 0; | 630 | return 0; |
503 | } | 631 | } |
504 | EXPORT_SYMBOL(cfcnfg_del_phy_layer); | 632 | EXPORT_SYMBOL(cfcnfg_del_phy_layer); |
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index 563145fdc4c3..e22671bed669 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/stddef.h> | 9 | #include <linux/stddef.h> |
8 | #include <linux/spinlock.h> | 10 | #include <linux/spinlock.h> |
9 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
@@ -15,7 +17,6 @@ | |||
15 | #define UTILITY_NAME_LENGTH 16 | 17 | #define UTILITY_NAME_LENGTH 16 |
16 | #define CFPKT_CTRL_PKT_LEN 20 | 18 | #define CFPKT_CTRL_PKT_LEN 20 |
17 | 19 | ||
18 | |||
19 | #ifdef CAIF_NO_LOOP | 20 | #ifdef CAIF_NO_LOOP |
20 | static int handle_loop(struct cfctrl *ctrl, | 21 | static int handle_loop(struct cfctrl *ctrl, |
21 | int cmd, struct cfpkt *pkt){ | 22 | int cmd, struct cfpkt *pkt){ |
@@ -36,7 +37,7 @@ struct cflayer *cfctrl_create(void) | |||
36 | struct cfctrl *this = | 37 | struct cfctrl *this = |
37 | kmalloc(sizeof(struct cfctrl), GFP_ATOMIC); | 38 | kmalloc(sizeof(struct cfctrl), GFP_ATOMIC); |
38 | if (!this) { | 39 | if (!this) { |
39 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 40 | pr_warn("Out of memory\n"); |
40 | return NULL; | 41 | return NULL; |
41 | } | 42 | } |
42 | caif_assert(offsetof(struct cfctrl, serv.layer) == 0); | 43 | caif_assert(offsetof(struct cfctrl, serv.layer) == 0); |
@@ -49,14 +50,31 @@ struct cflayer *cfctrl_create(void) | |||
49 | this->serv.layer.receive = cfctrl_recv; | 50 | this->serv.layer.receive = cfctrl_recv; |
50 | sprintf(this->serv.layer.name, "ctrl"); | 51 | sprintf(this->serv.layer.name, "ctrl"); |
51 | this->serv.layer.ctrlcmd = cfctrl_ctrlcmd; | 52 | this->serv.layer.ctrlcmd = cfctrl_ctrlcmd; |
53 | #ifndef CAIF_NO_LOOP | ||
52 | spin_lock_init(&this->loop_linkid_lock); | 54 | spin_lock_init(&this->loop_linkid_lock); |
55 | this->loop_linkid = 1; | ||
56 | #endif | ||
53 | spin_lock_init(&this->info_list_lock); | 57 | spin_lock_init(&this->info_list_lock); |
54 | INIT_LIST_HEAD(&this->list); | 58 | INIT_LIST_HEAD(&this->list); |
55 | this->loop_linkid = 1; | ||
56 | return &this->serv.layer; | 59 | return &this->serv.layer; |
57 | } | 60 | } |
58 | 61 | ||
59 | static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2) | 62 | void cfctrl_remove(struct cflayer *layer) |
63 | { | ||
64 | struct cfctrl_request_info *p, *tmp; | ||
65 | struct cfctrl *ctrl = container_obj(layer); | ||
66 | |||
67 | spin_lock_bh(&ctrl->info_list_lock); | ||
68 | list_for_each_entry_safe(p, tmp, &ctrl->list, list) { | ||
69 | list_del(&p->list); | ||
70 | kfree(p); | ||
71 | } | ||
72 | spin_unlock_bh(&ctrl->info_list_lock); | ||
73 | kfree(layer); | ||
74 | } | ||
75 | |||
76 | static bool param_eq(const struct cfctrl_link_param *p1, | ||
77 | const struct cfctrl_link_param *p2) | ||
60 | { | 78 | { |
61 | bool eq = | 79 | bool eq = |
62 | p1->linktype == p2->linktype && | 80 | p1->linktype == p2->linktype && |
@@ -98,8 +116,8 @@ static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2) | |||
98 | return false; | 116 | return false; |
99 | } | 117 | } |
100 | 118 | ||
101 | bool cfctrl_req_eq(struct cfctrl_request_info *r1, | 119 | static bool cfctrl_req_eq(const struct cfctrl_request_info *r1, |
102 | struct cfctrl_request_info *r2) | 120 | const struct cfctrl_request_info *r2) |
103 | { | 121 | { |
104 | if (r1->cmd != r2->cmd) | 122 | if (r1->cmd != r2->cmd) |
105 | return false; | 123 | return false; |
@@ -110,31 +128,28 @@ bool cfctrl_req_eq(struct cfctrl_request_info *r1, | |||
110 | } | 128 | } |
111 | 129 | ||
112 | /* Insert request at the end */ | 130 | /* Insert request at the end */ |
113 | void cfctrl_insert_req(struct cfctrl *ctrl, | 131 | static void cfctrl_insert_req(struct cfctrl *ctrl, |
114 | struct cfctrl_request_info *req) | 132 | struct cfctrl_request_info *req) |
115 | { | 133 | { |
116 | spin_lock(&ctrl->info_list_lock); | 134 | spin_lock_bh(&ctrl->info_list_lock); |
117 | atomic_inc(&ctrl->req_seq_no); | 135 | atomic_inc(&ctrl->req_seq_no); |
118 | req->sequence_no = atomic_read(&ctrl->req_seq_no); | 136 | req->sequence_no = atomic_read(&ctrl->req_seq_no); |
119 | list_add_tail(&req->list, &ctrl->list); | 137 | list_add_tail(&req->list, &ctrl->list); |
120 | spin_unlock(&ctrl->info_list_lock); | 138 | spin_unlock_bh(&ctrl->info_list_lock); |
121 | } | 139 | } |
122 | 140 | ||
123 | /* Compare and remove request */ | 141 | /* Compare and remove request */ |
124 | struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, | 142 | static struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, |
125 | struct cfctrl_request_info *req) | 143 | struct cfctrl_request_info *req) |
126 | { | 144 | { |
127 | struct cfctrl_request_info *p, *tmp, *first; | 145 | struct cfctrl_request_info *p, *tmp, *first; |
128 | 146 | ||
129 | spin_lock(&ctrl->info_list_lock); | ||
130 | first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list); | 147 | first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list); |
131 | 148 | ||
132 | list_for_each_entry_safe(p, tmp, &ctrl->list, list) { | 149 | list_for_each_entry_safe(p, tmp, &ctrl->list, list) { |
133 | if (cfctrl_req_eq(req, p)) { | 150 | if (cfctrl_req_eq(req, p)) { |
134 | if (p != first) | 151 | if (p != first) |
135 | pr_warning("CAIF: %s(): Requests are not " | 152 | pr_warn("Requests are not received in order\n"); |
136 | "received in order\n", | ||
137 | __func__); | ||
138 | 153 | ||
139 | atomic_set(&ctrl->rsp_seq_no, | 154 | atomic_set(&ctrl->rsp_seq_no, |
140 | p->sequence_no); | 155 | p->sequence_no); |
@@ -144,7 +159,6 @@ struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, | |||
144 | } | 159 | } |
145 | p = NULL; | 160 | p = NULL; |
146 | out: | 161 | out: |
147 | spin_unlock(&ctrl->info_list_lock); | ||
148 | return p; | 162 | return p; |
149 | } | 163 | } |
150 | 164 | ||
@@ -154,16 +168,6 @@ struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer) | |||
154 | return &this->res; | 168 | return &this->res; |
155 | } | 169 | } |
156 | 170 | ||
157 | void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn) | ||
158 | { | ||
159 | this->dn = dn; | ||
160 | } | ||
161 | |||
162 | void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up) | ||
163 | { | ||
164 | this->up = up; | ||
165 | } | ||
166 | |||
167 | static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl) | 171 | static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl) |
168 | { | 172 | { |
169 | info->hdr_len = 0; | 173 | info->hdr_len = 0; |
@@ -174,10 +178,14 @@ static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl) | |||
174 | void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid) | 178 | void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid) |
175 | { | 179 | { |
176 | struct cfctrl *cfctrl = container_obj(layer); | 180 | struct cfctrl *cfctrl = container_obj(layer); |
177 | int ret; | ||
178 | struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); | 181 | struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); |
182 | struct cflayer *dn = cfctrl->serv.layer.dn; | ||
179 | if (!pkt) { | 183 | if (!pkt) { |
180 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 184 | pr_warn("Out of memory\n"); |
185 | return; | ||
186 | } | ||
187 | if (!dn) { | ||
188 | pr_debug("not able to send enum request\n"); | ||
181 | return; | 189 | return; |
182 | } | 190 | } |
183 | caif_assert(offsetof(struct cfctrl, serv.layer) == 0); | 191 | caif_assert(offsetof(struct cfctrl, serv.layer) == 0); |
@@ -186,13 +194,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid) | |||
186 | cfctrl->serv.dev_info.id = physlinkid; | 194 | cfctrl->serv.dev_info.id = physlinkid; |
187 | cfpkt_addbdy(pkt, CFCTRL_CMD_ENUM); | 195 | cfpkt_addbdy(pkt, CFCTRL_CMD_ENUM); |
188 | cfpkt_addbdy(pkt, physlinkid); | 196 | cfpkt_addbdy(pkt, physlinkid); |
189 | ret = | 197 | dn->transmit(dn, pkt); |
190 | cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); | ||
191 | if (ret < 0) { | ||
192 | pr_err("CAIF: %s(): Could not transmit enum message\n", | ||
193 | __func__); | ||
194 | cfpkt_destroy(pkt); | ||
195 | } | ||
196 | } | 198 | } |
197 | 199 | ||
198 | int cfctrl_linkup_request(struct cflayer *layer, | 200 | int cfctrl_linkup_request(struct cflayer *layer, |
@@ -206,14 +208,29 @@ int cfctrl_linkup_request(struct cflayer *layer, | |||
206 | struct cfctrl_request_info *req; | 208 | struct cfctrl_request_info *req; |
207 | int ret; | 209 | int ret; |
208 | char utility_name[16]; | 210 | char utility_name[16]; |
209 | struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); | 211 | struct cfpkt *pkt; |
212 | struct cflayer *dn = cfctrl->serv.layer.dn; | ||
213 | |||
214 | if (!dn) { | ||
215 | pr_debug("not able to send linkup request\n"); | ||
216 | return -ENODEV; | ||
217 | } | ||
218 | |||
219 | if (cfctrl_cancel_req(layer, user_layer) > 0) { | ||
220 | /* Slight Paranoia, check if already connecting */ | ||
221 | pr_err("Duplicate connect request for same client\n"); | ||
222 | WARN_ON(1); | ||
223 | return -EALREADY; | ||
224 | } | ||
225 | |||
226 | pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); | ||
210 | if (!pkt) { | 227 | if (!pkt) { |
211 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 228 | pr_warn("Out of memory\n"); |
212 | return -ENOMEM; | 229 | return -ENOMEM; |
213 | } | 230 | } |
214 | cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP); | 231 | cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP); |
215 | cfpkt_addbdy(pkt, (param->chtype << 4) + param->linktype); | 232 | cfpkt_addbdy(pkt, (param->chtype << 4) | param->linktype); |
216 | cfpkt_addbdy(pkt, (param->priority << 3) + param->phyid); | 233 | cfpkt_addbdy(pkt, (param->priority << 3) | param->phyid); |
217 | cfpkt_addbdy(pkt, param->endpoint & 0x03); | 234 | cfpkt_addbdy(pkt, param->endpoint & 0x03); |
218 | 235 | ||
219 | switch (param->linktype) { | 236 | switch (param->linktype) { |
@@ -253,13 +270,13 @@ int cfctrl_linkup_request(struct cflayer *layer, | |||
253 | param->u.utility.paramlen); | 270 | param->u.utility.paramlen); |
254 | break; | 271 | break; |
255 | default: | 272 | default: |
256 | pr_warning("CAIF: %s():Request setup of bad link type = %d\n", | 273 | pr_warn("Request setup of bad link type = %d\n", |
257 | __func__, param->linktype); | 274 | param->linktype); |
258 | return -EINVAL; | 275 | return -EINVAL; |
259 | } | 276 | } |
260 | req = kzalloc(sizeof(*req), GFP_KERNEL); | 277 | req = kzalloc(sizeof(*req), GFP_KERNEL); |
261 | if (!req) { | 278 | if (!req) { |
262 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 279 | pr_warn("Out of memory\n"); |
263 | return -ENOMEM; | 280 | return -ENOMEM; |
264 | } | 281 | } |
265 | req->client_layer = user_layer; | 282 | req->client_layer = user_layer; |
@@ -274,12 +291,15 @@ int cfctrl_linkup_request(struct cflayer *layer, | |||
274 | */ | 291 | */ |
275 | cfpkt_info(pkt)->dev_info->id = param->phyid; | 292 | cfpkt_info(pkt)->dev_info->id = param->phyid; |
276 | ret = | 293 | ret = |
277 | cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); | 294 | dn->transmit(dn, pkt); |
278 | if (ret < 0) { | 295 | if (ret < 0) { |
279 | pr_err("CAIF: %s(): Could not transmit linksetup request\n", | 296 | int count; |
280 | __func__); | 297 | |
281 | cfpkt_destroy(pkt); | 298 | count = cfctrl_cancel_req(&cfctrl->serv.layer, |
282 | return -ENODEV; | 299 | user_layer); |
300 | if (count != 1) | ||
301 | pr_err("Could not remove request (%d)", count); | ||
302 | return -ENODEV; | ||
283 | } | 303 | } |
284 | return 0; | 304 | return 0; |
285 | } | 305 | } |
@@ -290,92 +310,46 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid, | |||
290 | int ret; | 310 | int ret; |
291 | struct cfctrl *cfctrl = container_obj(layer); | 311 | struct cfctrl *cfctrl = container_obj(layer); |
292 | struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); | 312 | struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); |
293 | if (!pkt) { | 313 | struct cflayer *dn = cfctrl->serv.layer.dn; |
294 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | ||
295 | return -ENOMEM; | ||
296 | } | ||
297 | cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY); | ||
298 | cfpkt_addbdy(pkt, channelid); | ||
299 | init_info(cfpkt_info(pkt), cfctrl); | ||
300 | ret = | ||
301 | cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); | ||
302 | if (ret < 0) { | ||
303 | pr_err("CAIF: %s(): Could not transmit link-down request\n", | ||
304 | __func__); | ||
305 | cfpkt_destroy(pkt); | ||
306 | } | ||
307 | return ret; | ||
308 | } | ||
309 | 314 | ||
310 | void cfctrl_sleep_req(struct cflayer *layer) | ||
311 | { | ||
312 | int ret; | ||
313 | struct cfctrl *cfctrl = container_obj(layer); | ||
314 | struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); | ||
315 | if (!pkt) { | 315 | if (!pkt) { |
316 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 316 | pr_warn("Out of memory\n"); |
317 | return; | 317 | return -ENOMEM; |
318 | } | 318 | } |
319 | cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP); | ||
320 | init_info(cfpkt_info(pkt), cfctrl); | ||
321 | ret = | ||
322 | cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); | ||
323 | if (ret < 0) | ||
324 | cfpkt_destroy(pkt); | ||
325 | } | ||
326 | 319 | ||
327 | void cfctrl_wake_req(struct cflayer *layer) | 320 | if (!dn) { |
328 | { | 321 | pr_debug("not able to send link-down request\n"); |
329 | int ret; | 322 | return -ENODEV; |
330 | struct cfctrl *cfctrl = container_obj(layer); | ||
331 | struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); | ||
332 | if (!pkt) { | ||
333 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | ||
334 | return; | ||
335 | } | 323 | } |
336 | cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE); | ||
337 | init_info(cfpkt_info(pkt), cfctrl); | ||
338 | ret = | ||
339 | cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); | ||
340 | if (ret < 0) | ||
341 | cfpkt_destroy(pkt); | ||
342 | } | ||
343 | 324 | ||
344 | void cfctrl_getstartreason_req(struct cflayer *layer) | 325 | cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY); |
345 | { | 326 | cfpkt_addbdy(pkt, channelid); |
346 | int ret; | ||
347 | struct cfctrl *cfctrl = container_obj(layer); | ||
348 | struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); | ||
349 | if (!pkt) { | ||
350 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | ||
351 | return; | ||
352 | } | ||
353 | cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON); | ||
354 | init_info(cfpkt_info(pkt), cfctrl); | 327 | init_info(cfpkt_info(pkt), cfctrl); |
355 | ret = | 328 | ret = |
356 | cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); | 329 | dn->transmit(dn, pkt); |
357 | if (ret < 0) | 330 | #ifndef CAIF_NO_LOOP |
358 | cfpkt_destroy(pkt); | 331 | cfctrl->loop_linkused[channelid] = 0; |
332 | #endif | ||
333 | return ret; | ||
359 | } | 334 | } |
360 | 335 | ||
361 | 336 | int cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer) | |
362 | void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer) | ||
363 | { | 337 | { |
364 | struct cfctrl_request_info *p, *tmp; | 338 | struct cfctrl_request_info *p, *tmp; |
365 | struct cfctrl *ctrl = container_obj(layr); | 339 | struct cfctrl *ctrl = container_obj(layr); |
366 | spin_lock(&ctrl->info_list_lock); | 340 | int found = 0; |
367 | pr_warning("CAIF: %s(): enter\n", __func__); | 341 | spin_lock_bh(&ctrl->info_list_lock); |
368 | 342 | ||
369 | list_for_each_entry_safe(p, tmp, &ctrl->list, list) { | 343 | list_for_each_entry_safe(p, tmp, &ctrl->list, list) { |
370 | if (p->client_layer == adap_layer) { | 344 | if (p->client_layer == adap_layer) { |
371 | pr_warning("CAIF: %s(): cancel req :%d\n", __func__, | ||
372 | p->sequence_no); | ||
373 | list_del(&p->list); | 345 | list_del(&p->list); |
374 | kfree(p); | 346 | kfree(p); |
347 | found++; | ||
375 | } | 348 | } |
376 | } | 349 | } |
377 | 350 | ||
378 | spin_unlock(&ctrl->info_list_lock); | 351 | spin_unlock_bh(&ctrl->info_list_lock); |
352 | return found; | ||
379 | } | 353 | } |
380 | 354 | ||
381 | static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) | 355 | static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) |
@@ -394,7 +368,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) | |||
394 | cfpkt_extr_head(pkt, &cmdrsp, 1); | 368 | cfpkt_extr_head(pkt, &cmdrsp, 1); |
395 | cmd = cmdrsp & CFCTRL_CMD_MASK; | 369 | cmd = cmdrsp & CFCTRL_CMD_MASK; |
396 | if (cmd != CFCTRL_CMD_LINK_ERR | 370 | if (cmd != CFCTRL_CMD_LINK_ERR |
397 | && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)) { | 371 | && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp) |
372 | && CFCTRL_ERR_BIT != (CFCTRL_ERR_BIT & cmdrsp)) { | ||
398 | if (handle_loop(cfctrl, cmd, pkt) != 0) | 373 | if (handle_loop(cfctrl, cmd, pkt) != 0) |
399 | cmdrsp |= CFCTRL_ERR_BIT; | 374 | cmdrsp |= CFCTRL_ERR_BIT; |
400 | } | 375 | } |
@@ -520,21 +495,20 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) | |||
520 | cfpkt_extr_head(pkt, ¶m, len); | 495 | cfpkt_extr_head(pkt, ¶m, len); |
521 | break; | 496 | break; |
522 | default: | 497 | default: |
523 | pr_warning("CAIF: %s(): Request setup " | 498 | pr_warn("Request setup, invalid type (%d)\n", |
524 | "- invalid link type (%d)", | 499 | serv); |
525 | __func__, serv); | ||
526 | goto error; | 500 | goto error; |
527 | } | 501 | } |
528 | 502 | ||
529 | rsp.cmd = cmd; | 503 | rsp.cmd = cmd; |
530 | rsp.param = linkparam; | 504 | rsp.param = linkparam; |
505 | spin_lock_bh(&cfctrl->info_list_lock); | ||
531 | req = cfctrl_remove_req(cfctrl, &rsp); | 506 | req = cfctrl_remove_req(cfctrl, &rsp); |
532 | 507 | ||
533 | if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) || | 508 | if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) || |
534 | cfpkt_erroneous(pkt)) { | 509 | cfpkt_erroneous(pkt)) { |
535 | pr_err("CAIF: %s(): Invalid O/E bit or parse " | 510 | pr_err("Invalid O/E bit or parse error " |
536 | "error on CAIF control channel", | 511 | "on CAIF control channel\n"); |
537 | __func__); | ||
538 | cfctrl->res.reject_rsp(cfctrl->serv.layer.up, | 512 | cfctrl->res.reject_rsp(cfctrl->serv.layer.up, |
539 | 0, | 513 | 0, |
540 | req ? req->client_layer | 514 | req ? req->client_layer |
@@ -549,6 +523,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) | |||
549 | 523 | ||
550 | if (req != NULL) | 524 | if (req != NULL) |
551 | kfree(req); | 525 | kfree(req); |
526 | |||
527 | spin_unlock_bh(&cfctrl->info_list_lock); | ||
552 | } | 528 | } |
553 | break; | 529 | break; |
554 | case CFCTRL_CMD_LINK_DESTROY: | 530 | case CFCTRL_CMD_LINK_DESTROY: |
@@ -556,8 +532,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) | |||
556 | cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid); | 532 | cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid); |
557 | break; | 533 | break; |
558 | case CFCTRL_CMD_LINK_ERR: | 534 | case CFCTRL_CMD_LINK_ERR: |
559 | pr_err("CAIF: %s(): Frame Error Indication received\n", | 535 | pr_err("Frame Error Indication received\n"); |
560 | __func__); | ||
561 | cfctrl->res.linkerror_ind(); | 536 | cfctrl->res.linkerror_ind(); |
562 | break; | 537 | break; |
563 | case CFCTRL_CMD_ENUM: | 538 | case CFCTRL_CMD_ENUM: |
@@ -576,7 +551,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) | |||
576 | cfctrl->res.radioset_rsp(); | 551 | cfctrl->res.radioset_rsp(); |
577 | break; | 552 | break; |
578 | default: | 553 | default: |
579 | pr_err("CAIF: %s(): Unrecognized Control Frame\n", __func__); | 554 | pr_err("Unrecognized Control Frame\n"); |
580 | goto error; | 555 | goto error; |
581 | break; | 556 | break; |
582 | } | 557 | } |
@@ -593,13 +568,28 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | |||
593 | switch (ctrl) { | 568 | switch (ctrl) { |
594 | case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: | 569 | case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: |
595 | case CAIF_CTRLCMD_FLOW_OFF_IND: | 570 | case CAIF_CTRLCMD_FLOW_OFF_IND: |
596 | spin_lock(&this->info_list_lock); | 571 | spin_lock_bh(&this->info_list_lock); |
597 | if (!list_empty(&this->list)) { | 572 | if (!list_empty(&this->list)) |
598 | pr_debug("CAIF: %s(): Received flow off in " | 573 | pr_debug("Received flow off in control layer\n"); |
599 | "control layer", __func__); | 574 | spin_unlock_bh(&this->info_list_lock); |
575 | break; | ||
576 | case _CAIF_CTRLCMD_PHYIF_DOWN_IND: { | ||
577 | struct cfctrl_request_info *p, *tmp; | ||
578 | |||
579 | /* Find all connect request and report failure */ | ||
580 | spin_lock_bh(&this->info_list_lock); | ||
581 | list_for_each_entry_safe(p, tmp, &this->list, list) { | ||
582 | if (p->param.phyid == phyid) { | ||
583 | list_del(&p->list); | ||
584 | p->client_layer->ctrlcmd(p->client_layer, | ||
585 | CAIF_CTRLCMD_INIT_FAIL_RSP, | ||
586 | phyid); | ||
587 | kfree(p); | ||
588 | } | ||
600 | } | 589 | } |
601 | spin_unlock(&this->info_list_lock); | 590 | spin_unlock_bh(&this->info_list_lock); |
602 | break; | 591 | break; |
592 | } | ||
603 | default: | 593 | default: |
604 | break; | 594 | break; |
605 | } | 595 | } |
@@ -609,27 +599,33 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | |||
609 | static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt) | 599 | static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt) |
610 | { | 600 | { |
611 | static int last_linkid; | 601 | static int last_linkid; |
602 | static int dec; | ||
612 | u8 linkid, linktype, tmp; | 603 | u8 linkid, linktype, tmp; |
613 | switch (cmd) { | 604 | switch (cmd) { |
614 | case CFCTRL_CMD_LINK_SETUP: | 605 | case CFCTRL_CMD_LINK_SETUP: |
615 | spin_lock(&ctrl->loop_linkid_lock); | 606 | spin_lock_bh(&ctrl->loop_linkid_lock); |
616 | for (linkid = last_linkid + 1; linkid < 255; linkid++) | 607 | if (!dec) { |
617 | if (!ctrl->loop_linkused[linkid]) | 608 | for (linkid = last_linkid + 1; linkid < 254; linkid++) |
618 | goto found; | 609 | if (!ctrl->loop_linkused[linkid]) |
619 | for (linkid = last_linkid - 1; linkid > 0; linkid--) | 610 | goto found; |
611 | } | ||
612 | dec = 1; | ||
613 | for (linkid = last_linkid - 1; linkid > 1; linkid--) | ||
620 | if (!ctrl->loop_linkused[linkid]) | 614 | if (!ctrl->loop_linkused[linkid]) |
621 | goto found; | 615 | goto found; |
622 | spin_unlock(&ctrl->loop_linkid_lock); | 616 | spin_unlock_bh(&ctrl->loop_linkid_lock); |
623 | pr_err("CAIF: %s(): Out of link-ids\n", __func__); | 617 | return -1; |
624 | return -EINVAL; | ||
625 | found: | 618 | found: |
619 | if (linkid < 10) | ||
620 | dec = 0; | ||
621 | |||
626 | if (!ctrl->loop_linkused[linkid]) | 622 | if (!ctrl->loop_linkused[linkid]) |
627 | ctrl->loop_linkused[linkid] = 1; | 623 | ctrl->loop_linkused[linkid] = 1; |
628 | 624 | ||
629 | last_linkid = linkid; | 625 | last_linkid = linkid; |
630 | 626 | ||
631 | cfpkt_add_trail(pkt, &linkid, 1); | 627 | cfpkt_add_trail(pkt, &linkid, 1); |
632 | spin_unlock(&ctrl->loop_linkid_lock); | 628 | spin_unlock_bh(&ctrl->loop_linkid_lock); |
633 | cfpkt_peek_head(pkt, &linktype, 1); | 629 | cfpkt_peek_head(pkt, &linktype, 1); |
634 | if (linktype == CFCTRL_SRV_UTIL) { | 630 | if (linktype == CFCTRL_SRV_UTIL) { |
635 | tmp = 0x01; | 631 | tmp = 0x01; |
@@ -639,10 +635,10 @@ found: | |||
639 | break; | 635 | break; |
640 | 636 | ||
641 | case CFCTRL_CMD_LINK_DESTROY: | 637 | case CFCTRL_CMD_LINK_DESTROY: |
642 | spin_lock(&ctrl->loop_linkid_lock); | 638 | spin_lock_bh(&ctrl->loop_linkid_lock); |
643 | cfpkt_peek_head(pkt, &linkid, 1); | 639 | cfpkt_peek_head(pkt, &linkid, 1); |
644 | ctrl->loop_linkused[linkid] = 0; | 640 | ctrl->loop_linkused[linkid] = 0; |
645 | spin_unlock(&ctrl->loop_linkid_lock); | 641 | spin_unlock_bh(&ctrl->loop_linkid_lock); |
646 | break; | 642 | break; |
647 | default: | 643 | default: |
648 | break; | 644 | break; |
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c index 676648cac8dd..11a2af4c162a 100644 --- a/net/caif/cfdbgl.c +++ b/net/caif/cfdbgl.c | |||
@@ -4,12 +4,16 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/stddef.h> | 9 | #include <linux/stddef.h> |
8 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
9 | #include <net/caif/caif_layer.h> | 11 | #include <net/caif/caif_layer.h> |
10 | #include <net/caif/cfsrvl.h> | 12 | #include <net/caif/cfsrvl.h> |
11 | #include <net/caif/cfpkt.h> | 13 | #include <net/caif/cfpkt.h> |
12 | 14 | ||
15 | #define container_obj(layr) ((struct cfsrvl *) layr) | ||
16 | |||
13 | static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt); | 17 | static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt); |
14 | static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt); | 18 | static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt); |
15 | 19 | ||
@@ -17,7 +21,7 @@ struct cflayer *cfdbgl_create(u8 channel_id, struct dev_info *dev_info) | |||
17 | { | 21 | { |
18 | struct cfsrvl *dbg = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); | 22 | struct cfsrvl *dbg = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); |
19 | if (!dbg) { | 23 | if (!dbg) { |
20 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 24 | pr_warn("Out of memory\n"); |
21 | return NULL; | 25 | return NULL; |
22 | } | 26 | } |
23 | caif_assert(offsetof(struct cfsrvl, layer) == 0); | 27 | caif_assert(offsetof(struct cfsrvl, layer) == 0); |
@@ -36,5 +40,17 @@ static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
36 | 40 | ||
37 | static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt) | 41 | static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt) |
38 | { | 42 | { |
43 | struct cfsrvl *service = container_obj(layr); | ||
44 | struct caif_payload_info *info; | ||
45 | int ret; | ||
46 | |||
47 | if (!cfsrvl_ready(service, &ret)) | ||
48 | return ret; | ||
49 | |||
50 | /* Add info for MUX-layer to route the packet out */ | ||
51 | info = cfpkt_info(pkt); | ||
52 | info->channel_id = service->layer.id; | ||
53 | info->dev_info = &service->dev_info; | ||
54 | |||
39 | return layr->dn->transmit(layr->dn, pkt); | 55 | return layr->dn->transmit(layr->dn, pkt); |
40 | } | 56 | } |
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c index ed9d53aff280..0382dec84fdc 100644 --- a/net/caif/cfdgml.c +++ b/net/caif/cfdgml.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/stddef.h> | 9 | #include <linux/stddef.h> |
8 | #include <linux/spinlock.h> | 10 | #include <linux/spinlock.h> |
9 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
@@ -11,12 +13,12 @@ | |||
11 | #include <net/caif/cfsrvl.h> | 13 | #include <net/caif/cfsrvl.h> |
12 | #include <net/caif/cfpkt.h> | 14 | #include <net/caif/cfpkt.h> |
13 | 15 | ||
16 | |||
14 | #define container_obj(layr) ((struct cfsrvl *) layr) | 17 | #define container_obj(layr) ((struct cfsrvl *) layr) |
15 | 18 | ||
16 | #define DGM_CMD_BIT 0x80 | 19 | #define DGM_CMD_BIT 0x80 |
17 | #define DGM_FLOW_OFF 0x81 | 20 | #define DGM_FLOW_OFF 0x81 |
18 | #define DGM_FLOW_ON 0x80 | 21 | #define DGM_FLOW_ON 0x80 |
19 | #define DGM_CTRL_PKT_SIZE 1 | ||
20 | #define DGM_MTU 1500 | 22 | #define DGM_MTU 1500 |
21 | 23 | ||
22 | static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt); | 24 | static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt); |
@@ -26,7 +28,7 @@ struct cflayer *cfdgml_create(u8 channel_id, struct dev_info *dev_info) | |||
26 | { | 28 | { |
27 | struct cfsrvl *dgm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); | 29 | struct cfsrvl *dgm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); |
28 | if (!dgm) { | 30 | if (!dgm) { |
29 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 31 | pr_warn("Out of memory\n"); |
30 | return NULL; | 32 | return NULL; |
31 | } | 33 | } |
32 | caif_assert(offsetof(struct cfsrvl, layer) == 0); | 34 | caif_assert(offsetof(struct cfsrvl, layer) == 0); |
@@ -49,14 +51,14 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
49 | caif_assert(layr->ctrlcmd != NULL); | 51 | caif_assert(layr->ctrlcmd != NULL); |
50 | 52 | ||
51 | if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { | 53 | if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { |
52 | pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); | 54 | pr_err("Packet is erroneous!\n"); |
53 | cfpkt_destroy(pkt); | 55 | cfpkt_destroy(pkt); |
54 | return -EPROTO; | 56 | return -EPROTO; |
55 | } | 57 | } |
56 | 58 | ||
57 | if ((cmd & DGM_CMD_BIT) == 0) { | 59 | if ((cmd & DGM_CMD_BIT) == 0) { |
58 | if (cfpkt_extr_head(pkt, &dgmhdr, 3) < 0) { | 60 | if (cfpkt_extr_head(pkt, &dgmhdr, 3) < 0) { |
59 | pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); | 61 | pr_err("Packet is erroneous!\n"); |
60 | cfpkt_destroy(pkt); | 62 | cfpkt_destroy(pkt); |
61 | return -EPROTO; | 63 | return -EPROTO; |
62 | } | 64 | } |
@@ -75,14 +77,14 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
75 | return 0; | 77 | return 0; |
76 | default: | 78 | default: |
77 | cfpkt_destroy(pkt); | 79 | cfpkt_destroy(pkt); |
78 | pr_info("CAIF: %s(): Unknown datagram control %d (0x%x)\n", | 80 | pr_info("Unknown datagram control %d (0x%x)\n", cmd, cmd); |
79 | __func__, cmd, cmd); | ||
80 | return -EPROTO; | 81 | return -EPROTO; |
81 | } | 82 | } |
82 | } | 83 | } |
83 | 84 | ||
84 | static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) | 85 | static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) |
85 | { | 86 | { |
87 | u8 packet_type; | ||
86 | u32 zero = 0; | 88 | u32 zero = 0; |
87 | struct caif_payload_info *info; | 89 | struct caif_payload_info *info; |
88 | struct cfsrvl *service = container_obj(layr); | 90 | struct cfsrvl *service = container_obj(layr); |
@@ -94,7 +96,9 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
94 | if (cfpkt_getlen(pkt) > DGM_MTU) | 96 | if (cfpkt_getlen(pkt) > DGM_MTU) |
95 | return -EMSGSIZE; | 97 | return -EMSGSIZE; |
96 | 98 | ||
97 | cfpkt_add_head(pkt, &zero, 4); | 99 | cfpkt_add_head(pkt, &zero, 3); |
100 | packet_type = 0x08; /* B9 set - UNCLASSIFIED */ | ||
101 | cfpkt_add_head(pkt, &packet_type, 1); | ||
98 | 102 | ||
99 | /* Add info for MUX-layer to route the packet out. */ | 103 | /* Add info for MUX-layer to route the packet out. */ |
100 | info = cfpkt_info(pkt); | 104 | info = cfpkt_info(pkt); |
@@ -104,10 +108,5 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
104 | */ | 108 | */ |
105 | info->hdr_len = 4; | 109 | info->hdr_len = 4; |
106 | info->dev_info = &service->dev_info; | 110 | info->dev_info = &service->dev_info; |
107 | ret = layr->dn->transmit(layr->dn, pkt); | 111 | return layr->dn->transmit(layr->dn, pkt); |
108 | if (ret < 0) { | ||
109 | u32 tmp32; | ||
110 | cfpkt_extr_head(pkt, &tmp32, 4); | ||
111 | } | ||
112 | return ret; | ||
113 | } | 112 | } |
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index e86a4ca3b217..04204b202718 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c | |||
@@ -6,10 +6,13 @@ | |||
6 | * License terms: GNU General Public License (GPL) version 2 | 6 | * License terms: GNU General Public License (GPL) version 2 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
10 | |||
9 | #include <linux/stddef.h> | 11 | #include <linux/stddef.h> |
10 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
11 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
12 | #include <linux/crc-ccitt.h> | 14 | #include <linux/crc-ccitt.h> |
15 | #include <linux/netdevice.h> | ||
13 | #include <net/caif/caif_layer.h> | 16 | #include <net/caif/caif_layer.h> |
14 | #include <net/caif/cfpkt.h> | 17 | #include <net/caif/cfpkt.h> |
15 | #include <net/caif/cffrml.h> | 18 | #include <net/caif/cffrml.h> |
@@ -19,6 +22,7 @@ | |||
19 | struct cffrml { | 22 | struct cffrml { |
20 | struct cflayer layer; | 23 | struct cflayer layer; |
21 | bool dofcs; /* !< FCS active */ | 24 | bool dofcs; /* !< FCS active */ |
25 | int __percpu *pcpu_refcnt; | ||
22 | }; | 26 | }; |
23 | 27 | ||
24 | static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); | 28 | static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); |
@@ -32,9 +36,15 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) | |||
32 | { | 36 | { |
33 | struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); | 37 | struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); |
34 | if (!this) { | 38 | if (!this) { |
35 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 39 | pr_warn("Out of memory\n"); |
40 | return NULL; | ||
41 | } | ||
42 | this->pcpu_refcnt = alloc_percpu(int); | ||
43 | if (this->pcpu_refcnt == NULL) { | ||
44 | kfree(this); | ||
36 | return NULL; | 45 | return NULL; |
37 | } | 46 | } |
47 | |||
38 | caif_assert(offsetof(struct cffrml, layer) == 0); | 48 | caif_assert(offsetof(struct cffrml, layer) == 0); |
39 | 49 | ||
40 | memset(this, 0, sizeof(struct cflayer)); | 50 | memset(this, 0, sizeof(struct cflayer)); |
@@ -47,6 +57,13 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) | |||
47 | return (struct cflayer *) this; | 57 | return (struct cflayer *) this; |
48 | } | 58 | } |
49 | 59 | ||
60 | void cffrml_free(struct cflayer *layer) | ||
61 | { | ||
62 | struct cffrml *this = container_obj(layer); | ||
63 | free_percpu(this->pcpu_refcnt); | ||
64 | kfree(layer); | ||
65 | } | ||
66 | |||
50 | void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) | 67 | void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) |
51 | { | 68 | { |
52 | this->up = up; | 69 | this->up = up; |
@@ -83,7 +100,7 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
83 | 100 | ||
84 | if (cfpkt_setlen(pkt, len) < 0) { | 101 | if (cfpkt_setlen(pkt, len) < 0) { |
85 | ++cffrml_rcv_error; | 102 | ++cffrml_rcv_error; |
86 | pr_err("CAIF: %s():Framing length error (%d)\n", __func__, len); | 103 | pr_err("Framing length error (%d)\n", len); |
87 | cfpkt_destroy(pkt); | 104 | cfpkt_destroy(pkt); |
88 | return -EPROTO; | 105 | return -EPROTO; |
89 | } | 106 | } |
@@ -99,17 +116,24 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
99 | cfpkt_add_trail(pkt, &tmp, 2); | 116 | cfpkt_add_trail(pkt, &tmp, 2); |
100 | ++cffrml_rcv_error; | 117 | ++cffrml_rcv_error; |
101 | ++cffrml_rcv_checsum_error; | 118 | ++cffrml_rcv_checsum_error; |
102 | pr_info("CAIF: %s(): Frame checksum error " | 119 | pr_info("Frame checksum error (0x%x != 0x%x)\n", |
103 | "(0x%x != 0x%x)\n", __func__, hdrchks, pktchks); | 120 | hdrchks, pktchks); |
104 | return -EILSEQ; | 121 | return -EILSEQ; |
105 | } | 122 | } |
106 | } | 123 | } |
107 | if (cfpkt_erroneous(pkt)) { | 124 | if (cfpkt_erroneous(pkt)) { |
108 | ++cffrml_rcv_error; | 125 | ++cffrml_rcv_error; |
109 | pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); | 126 | pr_err("Packet is erroneous!\n"); |
110 | cfpkt_destroy(pkt); | 127 | cfpkt_destroy(pkt); |
111 | return -EPROTO; | 128 | return -EPROTO; |
112 | } | 129 | } |
130 | |||
131 | if (layr->up == NULL) { | ||
132 | pr_err("Layr up is missing!\n"); | ||
133 | cfpkt_destroy(pkt); | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
113 | return layr->up->receive(layr->up, pkt); | 137 | return layr->up->receive(layr->up, pkt); |
114 | } | 138 | } |
115 | 139 | ||
@@ -118,7 +142,6 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
118 | int tmp; | 142 | int tmp; |
119 | u16 chks; | 143 | u16 chks; |
120 | u16 len; | 144 | u16 len; |
121 | int ret; | ||
122 | struct cffrml *this = container_obj(layr); | 145 | struct cffrml *this = container_obj(layr); |
123 | if (this->dofcs) { | 146 | if (this->dofcs) { |
124 | chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); | 147 | chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); |
@@ -132,20 +155,45 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
132 | cfpkt_add_head(pkt, &tmp, 2); | 155 | cfpkt_add_head(pkt, &tmp, 2); |
133 | cfpkt_info(pkt)->hdr_len += 2; | 156 | cfpkt_info(pkt)->hdr_len += 2; |
134 | if (cfpkt_erroneous(pkt)) { | 157 | if (cfpkt_erroneous(pkt)) { |
135 | pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); | 158 | pr_err("Packet is erroneous!\n"); |
159 | cfpkt_destroy(pkt); | ||
136 | return -EPROTO; | 160 | return -EPROTO; |
137 | } | 161 | } |
138 | ret = layr->dn->transmit(layr->dn, pkt); | 162 | |
139 | if (ret < 0) { | 163 | if (layr->dn == NULL) { |
140 | /* Remove header on faulty packet. */ | 164 | cfpkt_destroy(pkt); |
141 | cfpkt_extr_head(pkt, &tmp, 2); | 165 | return -ENODEV; |
166 | |||
142 | } | 167 | } |
143 | return ret; | 168 | return layr->dn->transmit(layr->dn, pkt); |
144 | } | 169 | } |
145 | 170 | ||
146 | static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | 171 | static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, |
147 | int phyid) | 172 | int phyid) |
148 | { | 173 | { |
149 | if (layr->up->ctrlcmd) | 174 | if (layr->up && layr->up->ctrlcmd) |
150 | layr->up->ctrlcmd(layr->up, ctrl, layr->id); | 175 | layr->up->ctrlcmd(layr->up, ctrl, layr->id); |
151 | } | 176 | } |
177 | |||
178 | void cffrml_put(struct cflayer *layr) | ||
179 | { | ||
180 | struct cffrml *this = container_obj(layr); | ||
181 | if (layr != NULL && this->pcpu_refcnt != NULL) | ||
182 | irqsafe_cpu_dec(*this->pcpu_refcnt); | ||
183 | } | ||
184 | |||
185 | void cffrml_hold(struct cflayer *layr) | ||
186 | { | ||
187 | struct cffrml *this = container_obj(layr); | ||
188 | if (layr != NULL && this->pcpu_refcnt != NULL) | ||
189 | irqsafe_cpu_inc(*this->pcpu_refcnt); | ||
190 | } | ||
191 | |||
192 | int cffrml_refcnt_read(struct cflayer *layr) | ||
193 | { | ||
194 | int i, refcnt = 0; | ||
195 | struct cffrml *this = container_obj(layr); | ||
196 | for_each_possible_cpu(i) | ||
197 | refcnt += *per_cpu_ptr(this->pcpu_refcnt, i); | ||
198 | return refcnt; | ||
199 | } | ||
diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c index 80c8d332b258..c23979e79dfa 100644 --- a/net/caif/cfmuxl.c +++ b/net/caif/cfmuxl.c | |||
@@ -3,9 +3,13 @@ | |||
3 | * Author: Sjur Brendeland/sjur.brandeland@stericsson.com | 3 | * Author: Sjur Brendeland/sjur.brandeland@stericsson.com |
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | |||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
6 | #include <linux/stddef.h> | 9 | #include <linux/stddef.h> |
7 | #include <linux/spinlock.h> | 10 | #include <linux/spinlock.h> |
8 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
12 | #include <linux/rculist.h> | ||
9 | #include <net/caif/cfpkt.h> | 13 | #include <net/caif/cfpkt.h> |
10 | #include <net/caif/cfmuxl.h> | 14 | #include <net/caif/cfmuxl.h> |
11 | #include <net/caif/cfsrvl.h> | 15 | #include <net/caif/cfsrvl.h> |
@@ -58,111 +62,88 @@ struct cflayer *cfmuxl_create(void) | |||
58 | return &this->layer; | 62 | return &this->layer; |
59 | } | 63 | } |
60 | 64 | ||
61 | int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid) | 65 | int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid) |
62 | { | 66 | { |
63 | struct cfmuxl *muxl = container_obj(layr); | 67 | struct cfmuxl *muxl = (struct cfmuxl *) layr; |
64 | spin_lock(&muxl->receive_lock); | 68 | |
65 | cfsrvl_get(up); | 69 | spin_lock_bh(&muxl->transmit_lock); |
66 | list_add(&up->node, &muxl->srvl_list); | 70 | list_add_rcu(&dn->node, &muxl->frml_list); |
67 | spin_unlock(&muxl->receive_lock); | 71 | spin_unlock_bh(&muxl->transmit_lock); |
68 | return 0; | 72 | return 0; |
69 | } | 73 | } |
70 | 74 | ||
71 | bool cfmuxl_is_phy_inuse(struct cflayer *layr, u8 phyid) | 75 | static struct cflayer *get_from_id(struct list_head *list, u16 id) |
72 | { | 76 | { |
73 | struct list_head *node; | 77 | struct cflayer *lyr; |
74 | struct cflayer *layer; | 78 | list_for_each_entry_rcu(lyr, list, node) { |
75 | struct cfmuxl *muxl = container_obj(layr); | 79 | if (lyr->id == id) |
76 | bool match = false; | 80 | return lyr; |
77 | spin_lock(&muxl->receive_lock); | ||
78 | |||
79 | list_for_each(node, &muxl->srvl_list) { | ||
80 | layer = list_entry(node, struct cflayer, node); | ||
81 | if (cfsrvl_phyid_match(layer, phyid)) { | ||
82 | match = true; | ||
83 | break; | ||
84 | } | ||
85 | |||
86 | } | 81 | } |
87 | spin_unlock(&muxl->receive_lock); | 82 | |
88 | return match; | 83 | return NULL; |
89 | } | 84 | } |
90 | 85 | ||
91 | u8 cfmuxl_get_phyid(struct cflayer *layr, u8 channel_id) | 86 | int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid) |
92 | { | 87 | { |
93 | struct cflayer *up; | ||
94 | int phyid; | ||
95 | struct cfmuxl *muxl = container_obj(layr); | 88 | struct cfmuxl *muxl = container_obj(layr); |
96 | spin_lock(&muxl->receive_lock); | 89 | struct cflayer *old; |
97 | up = get_up(muxl, channel_id); | ||
98 | if (up != NULL) | ||
99 | phyid = cfsrvl_getphyid(up); | ||
100 | else | ||
101 | phyid = 0; | ||
102 | spin_unlock(&muxl->receive_lock); | ||
103 | return phyid; | ||
104 | } | ||
105 | 90 | ||
106 | int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid) | 91 | spin_lock_bh(&muxl->receive_lock); |
107 | { | ||
108 | struct cfmuxl *muxl = (struct cfmuxl *) layr; | ||
109 | spin_lock(&muxl->transmit_lock); | ||
110 | list_add(&dn->node, &muxl->frml_list); | ||
111 | spin_unlock(&muxl->transmit_lock); | ||
112 | return 0; | ||
113 | } | ||
114 | 92 | ||
115 | static struct cflayer *get_from_id(struct list_head *list, u16 id) | 93 | /* Two entries with same id is wrong, so remove old layer from mux */ |
116 | { | 94 | old = get_from_id(&muxl->srvl_list, linkid); |
117 | struct list_head *node; | 95 | if (old != NULL) |
118 | struct cflayer *layer; | 96 | list_del_rcu(&old->node); |
119 | list_for_each(node, list) { | 97 | |
120 | layer = list_entry(node, struct cflayer, node); | 98 | list_add_rcu(&up->node, &muxl->srvl_list); |
121 | if (layer->id == id) | 99 | spin_unlock_bh(&muxl->receive_lock); |
122 | return layer; | 100 | |
123 | } | 101 | return 0; |
124 | return NULL; | ||
125 | } | 102 | } |
126 | 103 | ||
127 | struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid) | 104 | struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid) |
128 | { | 105 | { |
129 | struct cfmuxl *muxl = container_obj(layr); | 106 | struct cfmuxl *muxl = container_obj(layr); |
130 | struct cflayer *dn; | 107 | struct cflayer *dn; |
131 | spin_lock(&muxl->transmit_lock); | 108 | int idx = phyid % DN_CACHE_SIZE; |
132 | memset(muxl->dn_cache, 0, sizeof(muxl->dn_cache)); | 109 | |
110 | spin_lock_bh(&muxl->transmit_lock); | ||
111 | rcu_assign_pointer(muxl->dn_cache[idx], NULL); | ||
133 | dn = get_from_id(&muxl->frml_list, phyid); | 112 | dn = get_from_id(&muxl->frml_list, phyid); |
134 | if (dn == NULL) { | 113 | if (dn == NULL) |
135 | spin_unlock(&muxl->transmit_lock); | 114 | goto out; |
136 | return NULL; | 115 | |
137 | } | 116 | list_del_rcu(&dn->node); |
138 | list_del(&dn->node); | ||
139 | caif_assert(dn != NULL); | 117 | caif_assert(dn != NULL); |
140 | spin_unlock(&muxl->transmit_lock); | 118 | out: |
119 | spin_unlock_bh(&muxl->transmit_lock); | ||
141 | return dn; | 120 | return dn; |
142 | } | 121 | } |
143 | 122 | ||
144 | /* Invariant: lock is taken */ | ||
145 | static struct cflayer *get_up(struct cfmuxl *muxl, u16 id) | 123 | static struct cflayer *get_up(struct cfmuxl *muxl, u16 id) |
146 | { | 124 | { |
147 | struct cflayer *up; | 125 | struct cflayer *up; |
148 | int idx = id % UP_CACHE_SIZE; | 126 | int idx = id % UP_CACHE_SIZE; |
149 | up = muxl->up_cache[idx]; | 127 | up = rcu_dereference(muxl->up_cache[idx]); |
150 | if (up == NULL || up->id != id) { | 128 | if (up == NULL || up->id != id) { |
129 | spin_lock_bh(&muxl->receive_lock); | ||
151 | up = get_from_id(&muxl->srvl_list, id); | 130 | up = get_from_id(&muxl->srvl_list, id); |
152 | muxl->up_cache[idx] = up; | 131 | rcu_assign_pointer(muxl->up_cache[idx], up); |
132 | spin_unlock_bh(&muxl->receive_lock); | ||
153 | } | 133 | } |
154 | return up; | 134 | return up; |
155 | } | 135 | } |
156 | 136 | ||
157 | /* Invariant: lock is taken */ | ||
158 | static struct cflayer *get_dn(struct cfmuxl *muxl, struct dev_info *dev_info) | 137 | static struct cflayer *get_dn(struct cfmuxl *muxl, struct dev_info *dev_info) |
159 | { | 138 | { |
160 | struct cflayer *dn; | 139 | struct cflayer *dn; |
161 | int idx = dev_info->id % DN_CACHE_SIZE; | 140 | int idx = dev_info->id % DN_CACHE_SIZE; |
162 | dn = muxl->dn_cache[idx]; | 141 | dn = rcu_dereference(muxl->dn_cache[idx]); |
163 | if (dn == NULL || dn->id != dev_info->id) { | 142 | if (dn == NULL || dn->id != dev_info->id) { |
143 | spin_lock_bh(&muxl->transmit_lock); | ||
164 | dn = get_from_id(&muxl->frml_list, dev_info->id); | 144 | dn = get_from_id(&muxl->frml_list, dev_info->id); |
165 | muxl->dn_cache[idx] = dn; | 145 | rcu_assign_pointer(muxl->dn_cache[idx], dn); |
146 | spin_unlock_bh(&muxl->transmit_lock); | ||
166 | } | 147 | } |
167 | return dn; | 148 | return dn; |
168 | } | 149 | } |
@@ -171,15 +152,22 @@ struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id) | |||
171 | { | 152 | { |
172 | struct cflayer *up; | 153 | struct cflayer *up; |
173 | struct cfmuxl *muxl = container_obj(layr); | 154 | struct cfmuxl *muxl = container_obj(layr); |
174 | spin_lock(&muxl->receive_lock); | 155 | int idx = id % UP_CACHE_SIZE; |
175 | up = get_up(muxl, id); | 156 | |
157 | if (id == 0) { | ||
158 | pr_warn("Trying to remove control layer\n"); | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
162 | spin_lock_bh(&muxl->receive_lock); | ||
163 | up = get_from_id(&muxl->srvl_list, id); | ||
176 | if (up == NULL) | 164 | if (up == NULL) |
177 | goto out; | 165 | goto out; |
178 | memset(muxl->up_cache, 0, sizeof(muxl->up_cache)); | 166 | |
179 | list_del(&up->node); | 167 | rcu_assign_pointer(muxl->up_cache[idx], NULL); |
180 | cfsrvl_put(up); | 168 | list_del_rcu(&up->node); |
181 | out: | 169 | out: |
182 | spin_unlock(&muxl->receive_lock); | 170 | spin_unlock_bh(&muxl->receive_lock); |
183 | return up; | 171 | return up; |
184 | } | 172 | } |
185 | 173 | ||
@@ -190,63 +178,96 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
190 | u8 id; | 178 | u8 id; |
191 | struct cflayer *up; | 179 | struct cflayer *up; |
192 | if (cfpkt_extr_head(pkt, &id, 1) < 0) { | 180 | if (cfpkt_extr_head(pkt, &id, 1) < 0) { |
193 | pr_err("CAIF: %s(): erroneous Caif Packet\n", __func__); | 181 | pr_err("erroneous Caif Packet\n"); |
194 | cfpkt_destroy(pkt); | 182 | cfpkt_destroy(pkt); |
195 | return -EPROTO; | 183 | return -EPROTO; |
196 | } | 184 | } |
197 | 185 | rcu_read_lock(); | |
198 | spin_lock(&muxl->receive_lock); | ||
199 | up = get_up(muxl, id); | 186 | up = get_up(muxl, id); |
200 | spin_unlock(&muxl->receive_lock); | 187 | |
201 | if (up == NULL) { | 188 | if (up == NULL) { |
202 | pr_info("CAIF: %s():Received data on unknown link ID = %d " | 189 | pr_debug("Received data on unknown link ID = %d (0x%x)" |
203 | "(0x%x) up == NULL", __func__, id, id); | 190 | " up == NULL", id, id); |
204 | cfpkt_destroy(pkt); | 191 | cfpkt_destroy(pkt); |
205 | /* | 192 | /* |
206 | * Don't return ERROR, since modem misbehaves and sends out | 193 | * Don't return ERROR, since modem misbehaves and sends out |
207 | * flow on before linksetup response. | 194 | * flow on before linksetup response. |
208 | */ | 195 | */ |
196 | |||
197 | rcu_read_unlock(); | ||
209 | return /* CFGLU_EPROT; */ 0; | 198 | return /* CFGLU_EPROT; */ 0; |
210 | } | 199 | } |
200 | |||
201 | /* We can't hold rcu_lock during receive, so take a ref count instead */ | ||
211 | cfsrvl_get(up); | 202 | cfsrvl_get(up); |
203 | rcu_read_unlock(); | ||
204 | |||
212 | ret = up->receive(up, pkt); | 205 | ret = up->receive(up, pkt); |
206 | |||
213 | cfsrvl_put(up); | 207 | cfsrvl_put(up); |
214 | return ret; | 208 | return ret; |
215 | } | 209 | } |
216 | 210 | ||
217 | static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt) | 211 | static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt) |
218 | { | 212 | { |
219 | int ret; | ||
220 | struct cfmuxl *muxl = container_obj(layr); | 213 | struct cfmuxl *muxl = container_obj(layr); |
214 | int err; | ||
221 | u8 linkid; | 215 | u8 linkid; |
222 | struct cflayer *dn; | 216 | struct cflayer *dn; |
223 | struct caif_payload_info *info = cfpkt_info(pkt); | 217 | struct caif_payload_info *info = cfpkt_info(pkt); |
224 | dn = get_dn(muxl, cfpkt_info(pkt)->dev_info); | 218 | BUG_ON(!info); |
219 | |||
220 | rcu_read_lock(); | ||
221 | |||
222 | dn = get_dn(muxl, info->dev_info); | ||
225 | if (dn == NULL) { | 223 | if (dn == NULL) { |
226 | pr_warning("CAIF: %s(): Send data on unknown phy " | 224 | pr_debug("Send data on unknown phy ID = %d (0x%x)\n", |
227 | "ID = %d (0x%x)\n", | 225 | info->dev_info->id, info->dev_info->id); |
228 | __func__, info->dev_info->id, info->dev_info->id); | 226 | rcu_read_unlock(); |
227 | cfpkt_destroy(pkt); | ||
229 | return -ENOTCONN; | 228 | return -ENOTCONN; |
230 | } | 229 | } |
230 | |||
231 | info->hdr_len += 1; | 231 | info->hdr_len += 1; |
232 | linkid = info->channel_id; | 232 | linkid = info->channel_id; |
233 | cfpkt_add_head(pkt, &linkid, 1); | 233 | cfpkt_add_head(pkt, &linkid, 1); |
234 | ret = dn->transmit(dn, pkt); | 234 | |
235 | /* Remove MUX protocol header upon error. */ | 235 | /* We can't hold rcu_lock during receive, so take a ref count instead */ |
236 | if (ret < 0) | 236 | cffrml_hold(dn); |
237 | cfpkt_extr_head(pkt, &linkid, 1); | 237 | |
238 | return ret; | 238 | rcu_read_unlock(); |
239 | |||
240 | err = dn->transmit(dn, pkt); | ||
241 | |||
242 | cffrml_put(dn); | ||
243 | return err; | ||
239 | } | 244 | } |
240 | 245 | ||
241 | static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | 246 | static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, |
242 | int phyid) | 247 | int phyid) |
243 | { | 248 | { |
244 | struct cfmuxl *muxl = container_obj(layr); | 249 | struct cfmuxl *muxl = container_obj(layr); |
245 | struct list_head *node; | ||
246 | struct cflayer *layer; | 250 | struct cflayer *layer; |
247 | list_for_each(node, &muxl->srvl_list) { | 251 | int idx; |
248 | layer = list_entry(node, struct cflayer, node); | 252 | |
249 | if (cfsrvl_phyid_match(layer, phyid)) | 253 | rcu_read_lock(); |
254 | list_for_each_entry_rcu(layer, &muxl->srvl_list, node) { | ||
255 | |||
256 | if (cfsrvl_phyid_match(layer, phyid) && layer->ctrlcmd) { | ||
257 | |||
258 | if ((ctrl == _CAIF_CTRLCMD_PHYIF_DOWN_IND || | ||
259 | ctrl == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND) && | ||
260 | layer->id != 0) { | ||
261 | |||
262 | idx = layer->id % UP_CACHE_SIZE; | ||
263 | spin_lock_bh(&muxl->receive_lock); | ||
264 | rcu_assign_pointer(muxl->up_cache[idx], NULL); | ||
265 | list_del_rcu(&layer->node); | ||
266 | spin_unlock_bh(&muxl->receive_lock); | ||
267 | } | ||
268 | /* NOTE: ctrlcmd is not allowed to block */ | ||
250 | layer->ctrlcmd(layer, ctrl, phyid); | 269 | layer->ctrlcmd(layer, ctrl, phyid); |
270 | } | ||
251 | } | 271 | } |
272 | rcu_read_unlock(); | ||
252 | } | 273 | } |
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c index c49a6695793a..75d4bfae1a78 100644 --- a/net/caif/cfpkt_skbuff.c +++ b/net/caif/cfpkt_skbuff.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/string.h> | 9 | #include <linux/string.h> |
8 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
9 | #include <linux/hardirq.h> | 11 | #include <linux/hardirq.h> |
@@ -12,11 +14,12 @@ | |||
12 | #define PKT_PREFIX 48 | 14 | #define PKT_PREFIX 48 |
13 | #define PKT_POSTFIX 2 | 15 | #define PKT_POSTFIX 2 |
14 | #define PKT_LEN_WHEN_EXTENDING 128 | 16 | #define PKT_LEN_WHEN_EXTENDING 128 |
15 | #define PKT_ERROR(pkt, errmsg) do { \ | 17 | #define PKT_ERROR(pkt, errmsg) \ |
16 | cfpkt_priv(pkt)->erronous = true; \ | 18 | do { \ |
17 | skb_reset_tail_pointer(&pkt->skb); \ | 19 | cfpkt_priv(pkt)->erronous = true; \ |
18 | pr_warning("CAIF: " errmsg);\ | 20 | skb_reset_tail_pointer(&pkt->skb); \ |
19 | } while (0) | 21 | pr_warn(errmsg); \ |
22 | } while (0) | ||
20 | 23 | ||
21 | struct cfpktq { | 24 | struct cfpktq { |
22 | struct sk_buff_head head; | 25 | struct sk_buff_head head; |
@@ -39,22 +42,22 @@ struct cfpkt_priv_data { | |||
39 | bool erronous; | 42 | bool erronous; |
40 | }; | 43 | }; |
41 | 44 | ||
42 | inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt) | 45 | static inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt) |
43 | { | 46 | { |
44 | return (struct cfpkt_priv_data *) pkt->skb.cb; | 47 | return (struct cfpkt_priv_data *) pkt->skb.cb; |
45 | } | 48 | } |
46 | 49 | ||
47 | inline bool is_erronous(struct cfpkt *pkt) | 50 | static inline bool is_erronous(struct cfpkt *pkt) |
48 | { | 51 | { |
49 | return cfpkt_priv(pkt)->erronous; | 52 | return cfpkt_priv(pkt)->erronous; |
50 | } | 53 | } |
51 | 54 | ||
52 | inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt) | 55 | static inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt) |
53 | { | 56 | { |
54 | return &pkt->skb; | 57 | return &pkt->skb; |
55 | } | 58 | } |
56 | 59 | ||
57 | inline struct cfpkt *skb_to_pkt(struct sk_buff *skb) | 60 | static inline struct cfpkt *skb_to_pkt(struct sk_buff *skb) |
58 | { | 61 | { |
59 | return (struct cfpkt *) skb; | 62 | return (struct cfpkt *) skb; |
60 | } | 63 | } |
@@ -94,21 +97,20 @@ inline struct cfpkt *cfpkt_create(u16 len) | |||
94 | { | 97 | { |
95 | return cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX); | 98 | return cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX); |
96 | } | 99 | } |
97 | EXPORT_SYMBOL(cfpkt_create); | ||
98 | 100 | ||
99 | void cfpkt_destroy(struct cfpkt *pkt) | 101 | void cfpkt_destroy(struct cfpkt *pkt) |
100 | { | 102 | { |
101 | struct sk_buff *skb = pkt_to_skb(pkt); | 103 | struct sk_buff *skb = pkt_to_skb(pkt); |
102 | kfree_skb(skb); | 104 | kfree_skb(skb); |
103 | } | 105 | } |
104 | EXPORT_SYMBOL(cfpkt_destroy); | 106 | |
105 | 107 | ||
106 | inline bool cfpkt_more(struct cfpkt *pkt) | 108 | inline bool cfpkt_more(struct cfpkt *pkt) |
107 | { | 109 | { |
108 | struct sk_buff *skb = pkt_to_skb(pkt); | 110 | struct sk_buff *skb = pkt_to_skb(pkt); |
109 | return skb->len > 0; | 111 | return skb->len > 0; |
110 | } | 112 | } |
111 | EXPORT_SYMBOL(cfpkt_more); | 113 | |
112 | 114 | ||
113 | int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len) | 115 | int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len) |
114 | { | 116 | { |
@@ -120,7 +122,6 @@ int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len) | |||
120 | return !cfpkt_extr_head(pkt, data, len) && | 122 | return !cfpkt_extr_head(pkt, data, len) && |
121 | !cfpkt_add_head(pkt, data, len); | 123 | !cfpkt_add_head(pkt, data, len); |
122 | } | 124 | } |
123 | EXPORT_SYMBOL(cfpkt_peek_head); | ||
124 | 125 | ||
125 | int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len) | 126 | int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len) |
126 | { | 127 | { |
@@ -130,13 +131,13 @@ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len) | |||
130 | return -EPROTO; | 131 | return -EPROTO; |
131 | 132 | ||
132 | if (unlikely(len > skb->len)) { | 133 | if (unlikely(len > skb->len)) { |
133 | PKT_ERROR(pkt, "cfpkt_extr_head read beyond end of packet\n"); | 134 | PKT_ERROR(pkt, "read beyond end of packet\n"); |
134 | return -EPROTO; | 135 | return -EPROTO; |
135 | } | 136 | } |
136 | 137 | ||
137 | if (unlikely(len > skb_headlen(skb))) { | 138 | if (unlikely(len > skb_headlen(skb))) { |
138 | if (unlikely(skb_linearize(skb) != 0)) { | 139 | if (unlikely(skb_linearize(skb) != 0)) { |
139 | PKT_ERROR(pkt, "cfpkt_extr_head linearize failed\n"); | 140 | PKT_ERROR(pkt, "linearize failed\n"); |
140 | return -EPROTO; | 141 | return -EPROTO; |
141 | } | 142 | } |
142 | } | 143 | } |
@@ -145,7 +146,6 @@ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len) | |||
145 | memcpy(data, from, len); | 146 | memcpy(data, from, len); |
146 | return 0; | 147 | return 0; |
147 | } | 148 | } |
148 | EXPORT_SYMBOL(cfpkt_extr_head); | ||
149 | 149 | ||
150 | int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) | 150 | int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) |
151 | { | 151 | { |
@@ -156,11 +156,11 @@ int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) | |||
156 | return -EPROTO; | 156 | return -EPROTO; |
157 | 157 | ||
158 | if (unlikely(skb_linearize(skb) != 0)) { | 158 | if (unlikely(skb_linearize(skb) != 0)) { |
159 | PKT_ERROR(pkt, "cfpkt_extr_trail linearize failed\n"); | 159 | PKT_ERROR(pkt, "linearize failed\n"); |
160 | return -EPROTO; | 160 | return -EPROTO; |
161 | } | 161 | } |
162 | if (unlikely(skb->data + len > skb_tail_pointer(skb))) { | 162 | if (unlikely(skb->data + len > skb_tail_pointer(skb))) { |
163 | PKT_ERROR(pkt, "cfpkt_extr_trail read beyond end of packet\n"); | 163 | PKT_ERROR(pkt, "read beyond end of packet\n"); |
164 | return -EPROTO; | 164 | return -EPROTO; |
165 | } | 165 | } |
166 | from = skb_tail_pointer(skb) - len; | 166 | from = skb_tail_pointer(skb) - len; |
@@ -168,13 +168,13 @@ int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) | |||
168 | memcpy(data, from, len); | 168 | memcpy(data, from, len); |
169 | return 0; | 169 | return 0; |
170 | } | 170 | } |
171 | EXPORT_SYMBOL(cfpkt_extr_trail); | 171 | |
172 | 172 | ||
173 | int cfpkt_pad_trail(struct cfpkt *pkt, u16 len) | 173 | int cfpkt_pad_trail(struct cfpkt *pkt, u16 len) |
174 | { | 174 | { |
175 | return cfpkt_add_body(pkt, NULL, len); | 175 | return cfpkt_add_body(pkt, NULL, len); |
176 | } | 176 | } |
177 | EXPORT_SYMBOL(cfpkt_pad_trail); | 177 | |
178 | 178 | ||
179 | int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) | 179 | int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) |
180 | { | 180 | { |
@@ -202,7 +202,7 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) | |||
202 | 202 | ||
203 | /* Make sure data is writable */ | 203 | /* Make sure data is writable */ |
204 | if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) { | 204 | if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) { |
205 | PKT_ERROR(pkt, "cfpkt_add_body: cow failed\n"); | 205 | PKT_ERROR(pkt, "cow failed\n"); |
206 | return -EPROTO; | 206 | return -EPROTO; |
207 | } | 207 | } |
208 | /* | 208 | /* |
@@ -211,8 +211,7 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) | |||
211 | * lengths of the top SKB. | 211 | * lengths of the top SKB. |
212 | */ | 212 | */ |
213 | if (lastskb != skb) { | 213 | if (lastskb != skb) { |
214 | pr_warning("CAIF: %s(): Packet is non-linear\n", | 214 | pr_warn("Packet is non-linear\n"); |
215 | __func__); | ||
216 | skb->len += len; | 215 | skb->len += len; |
217 | skb->data_len += len; | 216 | skb->data_len += len; |
218 | } | 217 | } |
@@ -224,13 +223,11 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) | |||
224 | memcpy(to, data, len); | 223 | memcpy(to, data, len); |
225 | return 0; | 224 | return 0; |
226 | } | 225 | } |
227 | EXPORT_SYMBOL(cfpkt_add_body); | ||
228 | 226 | ||
229 | inline int cfpkt_addbdy(struct cfpkt *pkt, u8 data) | 227 | inline int cfpkt_addbdy(struct cfpkt *pkt, u8 data) |
230 | { | 228 | { |
231 | return cfpkt_add_body(pkt, &data, 1); | 229 | return cfpkt_add_body(pkt, &data, 1); |
232 | } | 230 | } |
233 | EXPORT_SYMBOL(cfpkt_addbdy); | ||
234 | 231 | ||
235 | int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) | 232 | int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) |
236 | { | 233 | { |
@@ -242,14 +239,14 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) | |||
242 | if (unlikely(is_erronous(pkt))) | 239 | if (unlikely(is_erronous(pkt))) |
243 | return -EPROTO; | 240 | return -EPROTO; |
244 | if (unlikely(skb_headroom(skb) < len)) { | 241 | if (unlikely(skb_headroom(skb) < len)) { |
245 | PKT_ERROR(pkt, "cfpkt_add_head: no headroom\n"); | 242 | PKT_ERROR(pkt, "no headroom\n"); |
246 | return -EPROTO; | 243 | return -EPROTO; |
247 | } | 244 | } |
248 | 245 | ||
249 | /* Make sure data is writable */ | 246 | /* Make sure data is writable */ |
250 | ret = skb_cow_data(skb, 0, &lastskb); | 247 | ret = skb_cow_data(skb, 0, &lastskb); |
251 | if (unlikely(ret < 0)) { | 248 | if (unlikely(ret < 0)) { |
252 | PKT_ERROR(pkt, "cfpkt_add_head: cow failed\n"); | 249 | PKT_ERROR(pkt, "cow failed\n"); |
253 | return ret; | 250 | return ret; |
254 | } | 251 | } |
255 | 252 | ||
@@ -257,20 +254,20 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) | |||
257 | memcpy(to, data, len); | 254 | memcpy(to, data, len); |
258 | return 0; | 255 | return 0; |
259 | } | 256 | } |
260 | EXPORT_SYMBOL(cfpkt_add_head); | 257 | |
261 | 258 | ||
262 | inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len) | 259 | inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len) |
263 | { | 260 | { |
264 | return cfpkt_add_body(pkt, data, len); | 261 | return cfpkt_add_body(pkt, data, len); |
265 | } | 262 | } |
266 | EXPORT_SYMBOL(cfpkt_add_trail); | 263 | |
267 | 264 | ||
268 | inline u16 cfpkt_getlen(struct cfpkt *pkt) | 265 | inline u16 cfpkt_getlen(struct cfpkt *pkt) |
269 | { | 266 | { |
270 | struct sk_buff *skb = pkt_to_skb(pkt); | 267 | struct sk_buff *skb = pkt_to_skb(pkt); |
271 | return skb->len; | 268 | return skb->len; |
272 | } | 269 | } |
273 | EXPORT_SYMBOL(cfpkt_getlen); | 270 | |
274 | 271 | ||
275 | inline u16 cfpkt_iterate(struct cfpkt *pkt, | 272 | inline u16 cfpkt_iterate(struct cfpkt *pkt, |
276 | u16 (*iter_func)(u16, void *, u16), | 273 | u16 (*iter_func)(u16, void *, u16), |
@@ -283,12 +280,12 @@ inline u16 cfpkt_iterate(struct cfpkt *pkt, | |||
283 | if (unlikely(is_erronous(pkt))) | 280 | if (unlikely(is_erronous(pkt))) |
284 | return -EPROTO; | 281 | return -EPROTO; |
285 | if (unlikely(skb_linearize(&pkt->skb) != 0)) { | 282 | if (unlikely(skb_linearize(&pkt->skb) != 0)) { |
286 | PKT_ERROR(pkt, "cfpkt_iterate: linearize failed\n"); | 283 | PKT_ERROR(pkt, "linearize failed\n"); |
287 | return -EPROTO; | 284 | return -EPROTO; |
288 | } | 285 | } |
289 | return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt)); | 286 | return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt)); |
290 | } | 287 | } |
291 | EXPORT_SYMBOL(cfpkt_iterate); | 288 | |
292 | 289 | ||
293 | int cfpkt_setlen(struct cfpkt *pkt, u16 len) | 290 | int cfpkt_setlen(struct cfpkt *pkt, u16 len) |
294 | { | 291 | { |
@@ -309,22 +306,10 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len) | |||
309 | 306 | ||
310 | /* Need to expand SKB */ | 307 | /* Need to expand SKB */ |
311 | if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len))) | 308 | if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len))) |
312 | PKT_ERROR(pkt, "cfpkt_setlen: skb_pad_trail failed\n"); | 309 | PKT_ERROR(pkt, "skb_pad_trail failed\n"); |
313 | 310 | ||
314 | return cfpkt_getlen(pkt); | 311 | return cfpkt_getlen(pkt); |
315 | } | 312 | } |
316 | EXPORT_SYMBOL(cfpkt_setlen); | ||
317 | |||
318 | struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len) | ||
319 | { | ||
320 | struct cfpkt *pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX); | ||
321 | if (!pkt) | ||
322 | return NULL; | ||
323 | if (unlikely(data != NULL)) | ||
324 | cfpkt_add_body(pkt, data, len); | ||
325 | return pkt; | ||
326 | } | ||
327 | EXPORT_SYMBOL(cfpkt_create_uplink); | ||
328 | 313 | ||
329 | struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, | 314 | struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, |
330 | struct cfpkt *addpkt, | 315 | struct cfpkt *addpkt, |
@@ -366,7 +351,6 @@ struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, | |||
366 | dst->len += addlen; | 351 | dst->len += addlen; |
367 | return skb_to_pkt(dst); | 352 | return skb_to_pkt(dst); |
368 | } | 353 | } |
369 | EXPORT_SYMBOL(cfpkt_append); | ||
370 | 354 | ||
371 | struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) | 355 | struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) |
372 | { | 356 | { |
@@ -380,8 +364,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) | |||
380 | return NULL; | 364 | return NULL; |
381 | 365 | ||
382 | if (skb->data + pos > skb_tail_pointer(skb)) { | 366 | if (skb->data + pos > skb_tail_pointer(skb)) { |
383 | PKT_ERROR(pkt, | 367 | PKT_ERROR(pkt, "trying to split beyond end of packet\n"); |
384 | "cfpkt_split: trying to split beyond end of packet"); | ||
385 | return NULL; | 368 | return NULL; |
386 | } | 369 | } |
387 | 370 | ||
@@ -405,175 +388,13 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) | |||
405 | skb2->len += len2nd; | 388 | skb2->len += len2nd; |
406 | return skb_to_pkt(skb2); | 389 | return skb_to_pkt(skb2); |
407 | } | 390 | } |
408 | EXPORT_SYMBOL(cfpkt_split); | ||
409 | |||
410 | char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen) | ||
411 | { | ||
412 | struct sk_buff *skb = pkt_to_skb(pkt); | ||
413 | char *p = buf; | ||
414 | int i; | ||
415 | |||
416 | /* | ||
417 | * Sanity check buffer length, it needs to be at least as large as | ||
418 | * the header info: ~=50+ bytes | ||
419 | */ | ||
420 | if (buflen < 50) | ||
421 | return NULL; | ||
422 | |||
423 | snprintf(buf, buflen, "%s: pkt:%p len:%ld(%ld+%ld) {%ld,%ld} data: [", | ||
424 | is_erronous(pkt) ? "ERRONOUS-SKB" : | ||
425 | (skb->data_len != 0 ? "COMPLEX-SKB" : "SKB"), | ||
426 | skb, | ||
427 | (long) skb->len, | ||
428 | (long) (skb_tail_pointer(skb) - skb->data), | ||
429 | (long) skb->data_len, | ||
430 | (long) (skb->data - skb->head), | ||
431 | (long) (skb_tail_pointer(skb) - skb->head)); | ||
432 | p = buf + strlen(buf); | ||
433 | |||
434 | for (i = 0; i < skb_tail_pointer(skb) - skb->data && i < 300; i++) { | ||
435 | if (p > buf + buflen - 10) { | ||
436 | sprintf(p, "..."); | ||
437 | p = buf + strlen(buf); | ||
438 | break; | ||
439 | } | ||
440 | sprintf(p, "%02x,", skb->data[i]); | ||
441 | p = buf + strlen(buf); | ||
442 | } | ||
443 | sprintf(p, "]\n"); | ||
444 | return buf; | ||
445 | } | ||
446 | EXPORT_SYMBOL(cfpkt_log_pkt); | ||
447 | 391 | ||
448 | int cfpkt_raw_append(struct cfpkt *pkt, void **buf, unsigned int buflen) | 392 | bool cfpkt_erroneous(struct cfpkt *pkt) |
449 | { | ||
450 | struct sk_buff *skb = pkt_to_skb(pkt); | ||
451 | struct sk_buff *lastskb; | ||
452 | |||
453 | caif_assert(buf != NULL); | ||
454 | if (unlikely(is_erronous(pkt))) | ||
455 | return -EPROTO; | ||
456 | /* Make sure SKB is writable */ | ||
457 | if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) { | ||
458 | PKT_ERROR(pkt, "cfpkt_raw_append: skb_cow_data failed\n"); | ||
459 | return -EPROTO; | ||
460 | } | ||
461 | |||
462 | if (unlikely(skb_linearize(skb) != 0)) { | ||
463 | PKT_ERROR(pkt, "cfpkt_raw_append: linearize failed\n"); | ||
464 | return -EPROTO; | ||
465 | } | ||
466 | |||
467 | if (unlikely(skb_tailroom(skb) < buflen)) { | ||
468 | PKT_ERROR(pkt, "cfpkt_raw_append: buffer too short - failed\n"); | ||
469 | return -EPROTO; | ||
470 | } | ||
471 | |||
472 | *buf = skb_put(skb, buflen); | ||
473 | return 1; | ||
474 | } | ||
475 | EXPORT_SYMBOL(cfpkt_raw_append); | ||
476 | |||
477 | int cfpkt_raw_extract(struct cfpkt *pkt, void **buf, unsigned int buflen) | ||
478 | { | ||
479 | struct sk_buff *skb = pkt_to_skb(pkt); | ||
480 | |||
481 | caif_assert(buf != NULL); | ||
482 | if (unlikely(is_erronous(pkt))) | ||
483 | return -EPROTO; | ||
484 | |||
485 | if (unlikely(buflen > skb->len)) { | ||
486 | PKT_ERROR(pkt, "cfpkt_raw_extract: buflen too large " | ||
487 | "- failed\n"); | ||
488 | return -EPROTO; | ||
489 | } | ||
490 | |||
491 | if (unlikely(buflen > skb_headlen(skb))) { | ||
492 | if (unlikely(skb_linearize(skb) != 0)) { | ||
493 | PKT_ERROR(pkt, "cfpkt_raw_extract: linearize failed\n"); | ||
494 | return -EPROTO; | ||
495 | } | ||
496 | } | ||
497 | |||
498 | *buf = skb->data; | ||
499 | skb_pull(skb, buflen); | ||
500 | |||
501 | return 1; | ||
502 | } | ||
503 | EXPORT_SYMBOL(cfpkt_raw_extract); | ||
504 | |||
505 | inline bool cfpkt_erroneous(struct cfpkt *pkt) | ||
506 | { | 393 | { |
507 | return cfpkt_priv(pkt)->erronous; | 394 | return cfpkt_priv(pkt)->erronous; |
508 | } | 395 | } |
509 | EXPORT_SYMBOL(cfpkt_erroneous); | ||
510 | |||
511 | struct cfpktq *cfpktq_create(void) | ||
512 | { | ||
513 | struct cfpktq *q = kmalloc(sizeof(struct cfpktq), GFP_ATOMIC); | ||
514 | if (!q) | ||
515 | return NULL; | ||
516 | skb_queue_head_init(&q->head); | ||
517 | atomic_set(&q->count, 0); | ||
518 | spin_lock_init(&q->lock); | ||
519 | return q; | ||
520 | } | ||
521 | EXPORT_SYMBOL(cfpktq_create); | ||
522 | |||
523 | void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt, unsigned short prio) | ||
524 | { | ||
525 | atomic_inc(&pktq->count); | ||
526 | spin_lock(&pktq->lock); | ||
527 | skb_queue_tail(&pktq->head, pkt_to_skb(pkt)); | ||
528 | spin_unlock(&pktq->lock); | ||
529 | |||
530 | } | ||
531 | EXPORT_SYMBOL(cfpkt_queue); | ||
532 | |||
533 | struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq) | ||
534 | { | ||
535 | struct cfpkt *tmp; | ||
536 | spin_lock(&pktq->lock); | ||
537 | tmp = skb_to_pkt(skb_peek(&pktq->head)); | ||
538 | spin_unlock(&pktq->lock); | ||
539 | return tmp; | ||
540 | } | ||
541 | EXPORT_SYMBOL(cfpkt_qpeek); | ||
542 | |||
543 | struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq) | ||
544 | { | ||
545 | struct cfpkt *pkt; | ||
546 | spin_lock(&pktq->lock); | ||
547 | pkt = skb_to_pkt(skb_dequeue(&pktq->head)); | ||
548 | if (pkt) { | ||
549 | atomic_dec(&pktq->count); | ||
550 | caif_assert(atomic_read(&pktq->count) >= 0); | ||
551 | } | ||
552 | spin_unlock(&pktq->lock); | ||
553 | return pkt; | ||
554 | } | ||
555 | EXPORT_SYMBOL(cfpkt_dequeue); | ||
556 | |||
557 | int cfpkt_qcount(struct cfpktq *pktq) | ||
558 | { | ||
559 | return atomic_read(&pktq->count); | ||
560 | } | ||
561 | EXPORT_SYMBOL(cfpkt_qcount); | ||
562 | |||
563 | struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt) | ||
564 | { | ||
565 | struct cfpkt *clone; | ||
566 | clone = skb_to_pkt(skb_clone(pkt_to_skb(pkt), GFP_ATOMIC)); | ||
567 | /* Free original packet. */ | ||
568 | cfpkt_destroy(pkt); | ||
569 | if (!clone) | ||
570 | return NULL; | ||
571 | return clone; | ||
572 | } | ||
573 | EXPORT_SYMBOL(cfpkt_clone_release); | ||
574 | 396 | ||
575 | struct caif_payload_info *cfpkt_info(struct cfpkt *pkt) | 397 | struct caif_payload_info *cfpkt_info(struct cfpkt *pkt) |
576 | { | 398 | { |
577 | return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb; | 399 | return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb; |
578 | } | 400 | } |
579 | EXPORT_SYMBOL(cfpkt_info); | ||
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index 9a699242d104..0deabb440051 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/stddef.h> | 9 | #include <linux/stddef.h> |
8 | #include <linux/spinlock.h> | 10 | #include <linux/spinlock.h> |
9 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
@@ -29,9 +31,9 @@ struct cfrfml { | |||
29 | spinlock_t sync; | 31 | spinlock_t sync; |
30 | }; | 32 | }; |
31 | 33 | ||
32 | static void cfrfml_release(struct kref *kref) | 34 | static void cfrfml_release(struct cflayer *layer) |
33 | { | 35 | { |
34 | struct cfsrvl *srvl = container_of(kref, struct cfsrvl, ref); | 36 | struct cfsrvl *srvl = container_of(layer, struct cfsrvl, layer); |
35 | struct cfrfml *rfml = container_obj(&srvl->layer); | 37 | struct cfrfml *rfml = container_obj(&srvl->layer); |
36 | 38 | ||
37 | if (rfml->incomplete_frm) | 39 | if (rfml->incomplete_frm) |
@@ -48,7 +50,7 @@ struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info, | |||
48 | kzalloc(sizeof(struct cfrfml), GFP_ATOMIC); | 50 | kzalloc(sizeof(struct cfrfml), GFP_ATOMIC); |
49 | 51 | ||
50 | if (!this) { | 52 | if (!this) { |
51 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 53 | pr_warn("Out of memory\n"); |
52 | return NULL; | 54 | return NULL; |
53 | } | 55 | } |
54 | 56 | ||
@@ -178,9 +180,7 @@ out: | |||
178 | cfpkt_destroy(rfml->incomplete_frm); | 180 | cfpkt_destroy(rfml->incomplete_frm); |
179 | rfml->incomplete_frm = NULL; | 181 | rfml->incomplete_frm = NULL; |
180 | 182 | ||
181 | pr_info("CAIF: %s(): " | 183 | pr_info("Connection error %d triggered on RFM link\n", err); |
182 | "Connection error %d triggered on RFM link\n", | ||
183 | __func__, err); | ||
184 | 184 | ||
185 | /* Trigger connection error upon failure.*/ | 185 | /* Trigger connection error upon failure.*/ |
186 | layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, | 186 | layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, |
@@ -193,7 +193,7 @@ out: | |||
193 | 193 | ||
194 | static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt) | 194 | static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt) |
195 | { | 195 | { |
196 | caif_assert(cfpkt_getlen(pkt) >= rfml->fragment_size); | 196 | caif_assert(cfpkt_getlen(pkt) < rfml->fragment_size); |
197 | 197 | ||
198 | /* Add info for MUX-layer to route the packet out. */ | 198 | /* Add info for MUX-layer to route the packet out. */ |
199 | cfpkt_info(pkt)->channel_id = rfml->serv.layer.id; | 199 | cfpkt_info(pkt)->channel_id = rfml->serv.layer.id; |
@@ -280,9 +280,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
280 | out: | 280 | out: |
281 | 281 | ||
282 | if (err != 0) { | 282 | if (err != 0) { |
283 | pr_info("CAIF: %s(): " | 283 | pr_info("Connection error %d triggered on RFM link\n", err); |
284 | "Connection error %d triggered on RFM link\n", | ||
285 | __func__, err); | ||
286 | /* Trigger connection error upon failure.*/ | 284 | /* Trigger connection error upon failure.*/ |
287 | 285 | ||
288 | layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, | 286 | layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, |
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c index a11fbd68a13d..2715c84cfa87 100644 --- a/net/caif/cfserl.c +++ b/net/caif/cfserl.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/stddef.h> | 9 | #include <linux/stddef.h> |
8 | #include <linux/spinlock.h> | 10 | #include <linux/spinlock.h> |
9 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
@@ -23,7 +25,6 @@ struct cfserl { | |||
23 | spinlock_t sync; | 25 | spinlock_t sync; |
24 | bool usestx; | 26 | bool usestx; |
25 | }; | 27 | }; |
26 | #define STXLEN(layr) (layr->usestx ? 1 : 0) | ||
27 | 28 | ||
28 | static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt); | 29 | static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt); |
29 | static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt); | 30 | static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt); |
@@ -34,7 +35,7 @@ struct cflayer *cfserl_create(int type, int instance, bool use_stx) | |||
34 | { | 35 | { |
35 | struct cfserl *this = kmalloc(sizeof(struct cfserl), GFP_ATOMIC); | 36 | struct cfserl *this = kmalloc(sizeof(struct cfserl), GFP_ATOMIC); |
36 | if (!this) { | 37 | if (!this) { |
37 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 38 | pr_warn("Out of memory\n"); |
38 | return NULL; | 39 | return NULL; |
39 | } | 40 | } |
40 | caif_assert(offsetof(struct cfserl, layer) == 0); | 41 | caif_assert(offsetof(struct cfserl, layer) == 0); |
@@ -178,15 +179,10 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) | |||
178 | static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt) | 179 | static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt) |
179 | { | 180 | { |
180 | struct cfserl *layr = container_obj(layer); | 181 | struct cfserl *layr = container_obj(layer); |
181 | int ret; | ||
182 | u8 tmp8 = CFSERL_STX; | 182 | u8 tmp8 = CFSERL_STX; |
183 | if (layr->usestx) | 183 | if (layr->usestx) |
184 | cfpkt_add_head(newpkt, &tmp8, 1); | 184 | cfpkt_add_head(newpkt, &tmp8, 1); |
185 | ret = layer->dn->transmit(layer->dn, newpkt); | 185 | return layer->dn->transmit(layer->dn, newpkt); |
186 | if (ret < 0) | ||
187 | cfpkt_extr_head(newpkt, &tmp8, 1); | ||
188 | |||
189 | return ret; | ||
190 | } | 186 | } |
191 | 187 | ||
192 | static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | 188 | static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, |
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c index f40939a91211..535a1e72b366 100644 --- a/net/caif/cfsrvl.c +++ b/net/caif/cfsrvl.c | |||
@@ -4,10 +4,13 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
8 | #include <linux/types.h> | 10 | #include <linux/types.h> |
9 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
10 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/module.h> | ||
11 | #include <net/caif/caif_layer.h> | 14 | #include <net/caif/caif_layer.h> |
12 | #include <net/caif/cfsrvl.h> | 15 | #include <net/caif/cfsrvl.h> |
13 | #include <net/caif/cfpkt.h> | 16 | #include <net/caif/cfpkt.h> |
@@ -25,8 +28,8 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | |||
25 | { | 28 | { |
26 | struct cfsrvl *service = container_obj(layr); | 29 | struct cfsrvl *service = container_obj(layr); |
27 | 30 | ||
28 | caif_assert(layr->up != NULL); | 31 | if (layr->up == NULL || layr->up->ctrlcmd == NULL) |
29 | caif_assert(layr->up->ctrlcmd != NULL); | 32 | return; |
30 | 33 | ||
31 | switch (ctrl) { | 34 | switch (ctrl) { |
32 | case CAIF_CTRLCMD_INIT_RSP: | 35 | case CAIF_CTRLCMD_INIT_RSP: |
@@ -79,8 +82,7 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, | |||
79 | layr->up->ctrlcmd(layr->up, ctrl, phyid); | 82 | layr->up->ctrlcmd(layr->up, ctrl, phyid); |
80 | break; | 83 | break; |
81 | default: | 84 | default: |
82 | pr_warning("CAIF: %s(): " | 85 | pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl); |
83 | "Unexpected ctrl in cfsrvl (%d)\n", __func__, ctrl); | ||
84 | /* We have both modem and phy flow on, send flow on */ | 86 | /* We have both modem and phy flow on, send flow on */ |
85 | layr->up->ctrlcmd(layr->up, ctrl, phyid); | 87 | layr->up->ctrlcmd(layr->up, ctrl, phyid); |
86 | service->phy_flow_on = true; | 88 | service->phy_flow_on = true; |
@@ -107,14 +109,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) | |||
107 | u8 flow_on = SRVL_FLOW_ON; | 109 | u8 flow_on = SRVL_FLOW_ON; |
108 | pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE); | 110 | pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE); |
109 | if (!pkt) { | 111 | if (!pkt) { |
110 | pr_warning("CAIF: %s(): Out of memory\n", | 112 | pr_warn("Out of memory\n"); |
111 | __func__); | ||
112 | return -ENOMEM; | 113 | return -ENOMEM; |
113 | } | 114 | } |
114 | 115 | ||
115 | if (cfpkt_add_head(pkt, &flow_on, 1) < 0) { | 116 | if (cfpkt_add_head(pkt, &flow_on, 1) < 0) { |
116 | pr_err("CAIF: %s(): Packet is erroneous!\n", | 117 | pr_err("Packet is erroneous!\n"); |
117 | __func__); | ||
118 | cfpkt_destroy(pkt); | 118 | cfpkt_destroy(pkt); |
119 | return -EPROTO; | 119 | return -EPROTO; |
120 | } | 120 | } |
@@ -131,14 +131,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) | |||
131 | u8 flow_off = SRVL_FLOW_OFF; | 131 | u8 flow_off = SRVL_FLOW_OFF; |
132 | pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE); | 132 | pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE); |
133 | if (!pkt) { | 133 | if (!pkt) { |
134 | pr_warning("CAIF: %s(): Out of memory\n", | 134 | pr_warn("Out of memory\n"); |
135 | __func__); | ||
136 | return -ENOMEM; | 135 | return -ENOMEM; |
137 | } | 136 | } |
138 | 137 | ||
139 | if (cfpkt_add_head(pkt, &flow_off, 1) < 0) { | 138 | if (cfpkt_add_head(pkt, &flow_off, 1) < 0) { |
140 | pr_err("CAIF: %s(): Packet is erroneous!\n", | 139 | pr_err("Packet is erroneous!\n"); |
141 | __func__); | ||
142 | cfpkt_destroy(pkt); | 140 | cfpkt_destroy(pkt); |
143 | return -EPROTO; | 141 | return -EPROTO; |
144 | } | 142 | } |
@@ -154,14 +152,9 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) | |||
154 | return -EINVAL; | 152 | return -EINVAL; |
155 | } | 153 | } |
156 | 154 | ||
157 | void cfservl_destroy(struct cflayer *layer) | 155 | static void cfsrvl_release(struct cflayer *layer) |
158 | { | ||
159 | kfree(layer); | ||
160 | } | ||
161 | |||
162 | void cfsrvl_release(struct kref *kref) | ||
163 | { | 156 | { |
164 | struct cfsrvl *service = container_of(kref, struct cfsrvl, ref); | 157 | struct cfsrvl *service = container_of(layer, struct cfsrvl, layer); |
165 | kfree(service); | 158 | kfree(service); |
166 | } | 159 | } |
167 | 160 | ||
@@ -181,10 +174,8 @@ void cfsrvl_init(struct cfsrvl *service, | |||
181 | service->dev_info = *dev_info; | 174 | service->dev_info = *dev_info; |
182 | service->supports_flowctrl = supports_flowctrl; | 175 | service->supports_flowctrl = supports_flowctrl; |
183 | service->release = cfsrvl_release; | 176 | service->release = cfsrvl_release; |
184 | kref_init(&service->ref); | ||
185 | } | 177 | } |
186 | 178 | ||
187 | |||
188 | bool cfsrvl_ready(struct cfsrvl *service, int *err) | 179 | bool cfsrvl_ready(struct cfsrvl *service, int *err) |
189 | { | 180 | { |
190 | if (service->open && service->modem_flow_on && service->phy_flow_on) | 181 | if (service->open && service->modem_flow_on && service->phy_flow_on) |
@@ -197,6 +188,7 @@ bool cfsrvl_ready(struct cfsrvl *service, int *err) | |||
197 | *err = -EAGAIN; | 188 | *err = -EAGAIN; |
198 | return false; | 189 | return false; |
199 | } | 190 | } |
191 | |||
200 | u8 cfsrvl_getphyid(struct cflayer *layer) | 192 | u8 cfsrvl_getphyid(struct cflayer *layer) |
201 | { | 193 | { |
202 | struct cfsrvl *servl = container_obj(layer); | 194 | struct cfsrvl *servl = container_obj(layer); |
@@ -208,3 +200,26 @@ bool cfsrvl_phyid_match(struct cflayer *layer, int phyid) | |||
208 | struct cfsrvl *servl = container_obj(layer); | 200 | struct cfsrvl *servl = container_obj(layer); |
209 | return servl->dev_info.id == phyid; | 201 | return servl->dev_info.id == phyid; |
210 | } | 202 | } |
203 | |||
204 | void caif_free_client(struct cflayer *adap_layer) | ||
205 | { | ||
206 | struct cfsrvl *servl; | ||
207 | if (adap_layer == NULL || adap_layer->dn == NULL) | ||
208 | return; | ||
209 | servl = container_obj(adap_layer->dn); | ||
210 | servl->release(&servl->layer); | ||
211 | } | ||
212 | EXPORT_SYMBOL(caif_free_client); | ||
213 | |||
214 | void caif_client_register_refcnt(struct cflayer *adapt_layer, | ||
215 | void (*hold)(struct cflayer *lyr), | ||
216 | void (*put)(struct cflayer *lyr)) | ||
217 | { | ||
218 | struct cfsrvl *service; | ||
219 | service = container_of(adapt_layer->dn, struct cfsrvl, layer); | ||
220 | |||
221 | WARN_ON(adapt_layer == NULL || adapt_layer->dn == NULL); | ||
222 | service->hold = hold; | ||
223 | service->put = put; | ||
224 | } | ||
225 | EXPORT_SYMBOL(caif_client_register_refcnt); | ||
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c index 02795aff57a4..98e027db18ed 100644 --- a/net/caif/cfutill.c +++ b/net/caif/cfutill.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
8 | #include <linux/types.h> | 10 | #include <linux/types.h> |
9 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
@@ -18,7 +20,7 @@ | |||
18 | #define UTIL_REMOTE_SHUTDOWN 0x82 | 20 | #define UTIL_REMOTE_SHUTDOWN 0x82 |
19 | #define UTIL_FLOW_OFF 0x81 | 21 | #define UTIL_FLOW_OFF 0x81 |
20 | #define UTIL_FLOW_ON 0x80 | 22 | #define UTIL_FLOW_ON 0x80 |
21 | #define UTIL_CTRL_PKT_SIZE 1 | 23 | |
22 | static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt); | 24 | static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt); |
23 | static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt); | 25 | static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt); |
24 | 26 | ||
@@ -26,7 +28,7 @@ struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info) | |||
26 | { | 28 | { |
27 | struct cfsrvl *util = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); | 29 | struct cfsrvl *util = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); |
28 | if (!util) { | 30 | if (!util) { |
29 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 31 | pr_warn("Out of memory\n"); |
30 | return NULL; | 32 | return NULL; |
31 | } | 33 | } |
32 | caif_assert(offsetof(struct cfsrvl, layer) == 0); | 34 | caif_assert(offsetof(struct cfsrvl, layer) == 0); |
@@ -47,7 +49,7 @@ static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
47 | caif_assert(layr->up->receive != NULL); | 49 | caif_assert(layr->up->receive != NULL); |
48 | caif_assert(layr->up->ctrlcmd != NULL); | 50 | caif_assert(layr->up->ctrlcmd != NULL); |
49 | if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { | 51 | if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { |
50 | pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); | 52 | pr_err("Packet is erroneous!\n"); |
51 | cfpkt_destroy(pkt); | 53 | cfpkt_destroy(pkt); |
52 | return -EPROTO; | 54 | return -EPROTO; |
53 | } | 55 | } |
@@ -64,16 +66,14 @@ static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
64 | cfpkt_destroy(pkt); | 66 | cfpkt_destroy(pkt); |
65 | return 0; | 67 | return 0; |
66 | case UTIL_REMOTE_SHUTDOWN: /* Remote Shutdown Request */ | 68 | case UTIL_REMOTE_SHUTDOWN: /* Remote Shutdown Request */ |
67 | pr_err("CAIF: %s(): REMOTE SHUTDOWN REQUEST RECEIVED\n", | 69 | pr_err("REMOTE SHUTDOWN REQUEST RECEIVED\n"); |
68 | __func__); | ||
69 | layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0); | 70 | layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0); |
70 | service->open = false; | 71 | service->open = false; |
71 | cfpkt_destroy(pkt); | 72 | cfpkt_destroy(pkt); |
72 | return 0; | 73 | return 0; |
73 | default: | 74 | default: |
74 | cfpkt_destroy(pkt); | 75 | cfpkt_destroy(pkt); |
75 | pr_warning("CAIF: %s(): Unknown service control %d (0x%x)\n", | 76 | pr_warn("Unknown service control %d (0x%x)\n", cmd, cmd); |
76 | __func__, cmd, cmd); | ||
77 | return -EPROTO; | 77 | return -EPROTO; |
78 | } | 78 | } |
79 | } | 79 | } |
@@ -100,10 +100,5 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
100 | */ | 100 | */ |
101 | info->hdr_len = 1; | 101 | info->hdr_len = 1; |
102 | info->dev_info = &service->dev_info; | 102 | info->dev_info = &service->dev_info; |
103 | ret = layr->dn->transmit(layr->dn, pkt); | 103 | return layr->dn->transmit(layr->dn, pkt); |
104 | if (ret < 0) { | ||
105 | u32 tmp32; | ||
106 | cfpkt_extr_head(pkt, &tmp32, 4); | ||
107 | } | ||
108 | return ret; | ||
109 | } | 104 | } |
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c index 77cc09faac9a..3ec83fbc2887 100644 --- a/net/caif/cfveil.c +++ b/net/caif/cfveil.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/stddef.h> | 9 | #include <linux/stddef.h> |
8 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
9 | #include <net/caif/caif_layer.h> | 11 | #include <net/caif/caif_layer.h> |
@@ -15,7 +17,7 @@ | |||
15 | #define VEI_FLOW_OFF 0x81 | 17 | #define VEI_FLOW_OFF 0x81 |
16 | #define VEI_FLOW_ON 0x80 | 18 | #define VEI_FLOW_ON 0x80 |
17 | #define VEI_SET_PIN 0x82 | 19 | #define VEI_SET_PIN 0x82 |
18 | #define VEI_CTRL_PKT_SIZE 1 | 20 | |
19 | #define container_obj(layr) container_of(layr, struct cfsrvl, layer) | 21 | #define container_obj(layr) container_of(layr, struct cfsrvl, layer) |
20 | 22 | ||
21 | static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt); | 23 | static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt); |
@@ -25,7 +27,7 @@ struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info) | |||
25 | { | 27 | { |
26 | struct cfsrvl *vei = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); | 28 | struct cfsrvl *vei = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); |
27 | if (!vei) { | 29 | if (!vei) { |
28 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 30 | pr_warn("Out of memory\n"); |
29 | return NULL; | 31 | return NULL; |
30 | } | 32 | } |
31 | caif_assert(offsetof(struct cfsrvl, layer) == 0); | 33 | caif_assert(offsetof(struct cfsrvl, layer) == 0); |
@@ -47,7 +49,7 @@ static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
47 | 49 | ||
48 | 50 | ||
49 | if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { | 51 | if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { |
50 | pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); | 52 | pr_err("Packet is erroneous!\n"); |
51 | cfpkt_destroy(pkt); | 53 | cfpkt_destroy(pkt); |
52 | return -EPROTO; | 54 | return -EPROTO; |
53 | } | 55 | } |
@@ -67,8 +69,7 @@ static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
67 | cfpkt_destroy(pkt); | 69 | cfpkt_destroy(pkt); |
68 | return 0; | 70 | return 0; |
69 | default: /* SET RS232 PIN */ | 71 | default: /* SET RS232 PIN */ |
70 | pr_warning("CAIF: %s():Unknown VEI control packet %d (0x%x)!\n", | 72 | pr_warn("Unknown VEI control packet %d (0x%x)!\n", cmd, cmd); |
71 | __func__, cmd, cmd); | ||
72 | cfpkt_destroy(pkt); | 73 | cfpkt_destroy(pkt); |
73 | return -EPROTO; | 74 | return -EPROTO; |
74 | } | 75 | } |
@@ -81,13 +82,14 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
81 | int ret; | 82 | int ret; |
82 | struct cfsrvl *service = container_obj(layr); | 83 | struct cfsrvl *service = container_obj(layr); |
83 | if (!cfsrvl_ready(service, &ret)) | 84 | if (!cfsrvl_ready(service, &ret)) |
84 | return ret; | 85 | goto err; |
85 | caif_assert(layr->dn != NULL); | 86 | caif_assert(layr->dn != NULL); |
86 | caif_assert(layr->dn->transmit != NULL); | 87 | caif_assert(layr->dn->transmit != NULL); |
87 | 88 | ||
88 | if (cfpkt_add_head(pkt, &tmp, 1) < 0) { | 89 | if (cfpkt_add_head(pkt, &tmp, 1) < 0) { |
89 | pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); | 90 | pr_err("Packet is erroneous!\n"); |
90 | return -EPROTO; | 91 | ret = -EPROTO; |
92 | goto err; | ||
91 | } | 93 | } |
92 | 94 | ||
93 | /* Add info-> for MUX-layer to route the packet out. */ | 95 | /* Add info-> for MUX-layer to route the packet out. */ |
@@ -95,8 +97,8 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
95 | info->channel_id = service->layer.id; | 97 | info->channel_id = service->layer.id; |
96 | info->hdr_len = 1; | 98 | info->hdr_len = 1; |
97 | info->dev_info = &service->dev_info; | 99 | info->dev_info = &service->dev_info; |
98 | ret = layr->dn->transmit(layr->dn, pkt); | 100 | return layr->dn->transmit(layr->dn, pkt); |
99 | if (ret < 0) | 101 | err: |
100 | cfpkt_extr_head(pkt, &tmp, 1); | 102 | cfpkt_destroy(pkt); |
101 | return ret; | 103 | return ret; |
102 | } | 104 | } |
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c index ada6ee2d48f5..b2f5989ad455 100644 --- a/net/caif/cfvidl.c +++ b/net/caif/cfvidl.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * License terms: GNU General Public License (GPL) version 2 | 4 | * License terms: GNU General Public License (GPL) version 2 |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
8 | |||
7 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
8 | #include <linux/types.h> | 10 | #include <linux/types.h> |
9 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
@@ -21,7 +23,7 @@ struct cflayer *cfvidl_create(u8 channel_id, struct dev_info *dev_info) | |||
21 | { | 23 | { |
22 | struct cfsrvl *vid = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); | 24 | struct cfsrvl *vid = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); |
23 | if (!vid) { | 25 | if (!vid) { |
24 | pr_warning("CAIF: %s(): Out of memory\n", __func__); | 26 | pr_warn("Out of memory\n"); |
25 | return NULL; | 27 | return NULL; |
26 | } | 28 | } |
27 | caif_assert(offsetof(struct cfsrvl, layer) == 0); | 29 | caif_assert(offsetof(struct cfsrvl, layer) == 0); |
@@ -38,7 +40,7 @@ static int cfvidl_receive(struct cflayer *layr, struct cfpkt *pkt) | |||
38 | { | 40 | { |
39 | u32 videoheader; | 41 | u32 videoheader; |
40 | if (cfpkt_extr_head(pkt, &videoheader, 4) < 0) { | 42 | if (cfpkt_extr_head(pkt, &videoheader, 4) < 0) { |
41 | pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); | 43 | pr_err("Packet is erroneous!\n"); |
42 | cfpkt_destroy(pkt); | 44 | cfpkt_destroy(pkt); |
43 | return -EPROTO; | 45 | return -EPROTO; |
44 | } | 46 | } |
@@ -58,8 +60,5 @@ static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
58 | info = cfpkt_info(pkt); | 60 | info = cfpkt_info(pkt); |
59 | info->channel_id = service->layer.id; | 61 | info->channel_id = service->layer.id; |
60 | info->dev_info = &service->dev_info; | 62 | info->dev_info = &service->dev_info; |
61 | ret = layr->dn->transmit(layr->dn, pkt); | 63 | return layr->dn->transmit(layr->dn, pkt); |
62 | if (ret < 0) | ||
63 | cfpkt_extr_head(pkt, &videoheader, 4); | ||
64 | return ret; | ||
65 | } | 64 | } |
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index 4293e190ec53..adbb424403d4 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c | |||
@@ -5,6 +5,8 @@ | |||
5 | * License terms: GNU General Public License (GPL) version 2 | 5 | * License terms: GNU General Public License (GPL) version 2 |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ | ||
9 | |||
8 | #include <linux/version.h> | 10 | #include <linux/version.h> |
9 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
10 | #include <linux/init.h> | 12 | #include <linux/init.h> |
@@ -18,7 +20,6 @@ | |||
18 | #include <linux/caif/if_caif.h> | 20 | #include <linux/caif/if_caif.h> |
19 | #include <net/rtnetlink.h> | 21 | #include <net/rtnetlink.h> |
20 | #include <net/caif/caif_layer.h> | 22 | #include <net/caif/caif_layer.h> |
21 | #include <net/caif/cfcnfg.h> | ||
22 | #include <net/caif/cfpkt.h> | 23 | #include <net/caif/cfpkt.h> |
23 | #include <net/caif/caif_dev.h> | 24 | #include <net/caif/caif_dev.h> |
24 | 25 | ||
@@ -28,9 +29,6 @@ | |||
28 | #define CONNECT_TIMEOUT (5 * HZ) | 29 | #define CONNECT_TIMEOUT (5 * HZ) |
29 | #define CAIF_NET_DEFAULT_QUEUE_LEN 500 | 30 | #define CAIF_NET_DEFAULT_QUEUE_LEN 500 |
30 | 31 | ||
31 | #undef pr_debug | ||
32 | #define pr_debug pr_warning | ||
33 | |||
34 | /*This list is protected by the rtnl lock. */ | 32 | /*This list is protected by the rtnl lock. */ |
35 | static LIST_HEAD(chnl_net_list); | 33 | static LIST_HEAD(chnl_net_list); |
36 | 34 | ||
@@ -77,21 +75,38 @@ static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt) | |||
77 | struct chnl_net *priv = container_of(layr, struct chnl_net, chnl); | 75 | struct chnl_net *priv = container_of(layr, struct chnl_net, chnl); |
78 | int pktlen; | 76 | int pktlen; |
79 | int err = 0; | 77 | int err = 0; |
78 | const u8 *ip_version; | ||
79 | u8 buf; | ||
80 | 80 | ||
81 | priv = container_of(layr, struct chnl_net, chnl); | 81 | priv = container_of(layr, struct chnl_net, chnl); |
82 | 82 | ||
83 | if (!priv) | 83 | if (!priv) |
84 | return -EINVAL; | 84 | return -EINVAL; |
85 | 85 | ||
86 | skb = (struct sk_buff *) cfpkt_tonative(pkt); | ||
87 | |||
86 | /* Get length of CAIF packet. */ | 88 | /* Get length of CAIF packet. */ |
87 | pktlen = cfpkt_getlen(pkt); | 89 | pktlen = skb->len; |
88 | 90 | ||
89 | skb = (struct sk_buff *) cfpkt_tonative(pkt); | ||
90 | /* Pass some minimum information and | 91 | /* Pass some minimum information and |
91 | * send the packet to the net stack. | 92 | * send the packet to the net stack. |
92 | */ | 93 | */ |
93 | skb->dev = priv->netdev; | 94 | skb->dev = priv->netdev; |
94 | skb->protocol = htons(ETH_P_IP); | 95 | |
96 | /* check the version of IP */ | ||
97 | ip_version = skb_header_pointer(skb, 0, 1, &buf); | ||
98 | if (!ip_version) | ||
99 | return -EINVAL; | ||
100 | switch (*ip_version >> 4) { | ||
101 | case 4: | ||
102 | skb->protocol = htons(ETH_P_IP); | ||
103 | break; | ||
104 | case 6: | ||
105 | skb->protocol = htons(ETH_P_IPV6); | ||
106 | break; | ||
107 | default: | ||
108 | return -EINVAL; | ||
109 | } | ||
95 | 110 | ||
96 | /* If we change the header in loop mode, the checksum is corrupted. */ | 111 | /* If we change the header in loop mode, the checksum is corrupted. */ |
97 | if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP) | 112 | if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP) |
@@ -124,26 +139,34 @@ static void close_work(struct work_struct *work) | |||
124 | struct chnl_net *dev = NULL; | 139 | struct chnl_net *dev = NULL; |
125 | struct list_head *list_node; | 140 | struct list_head *list_node; |
126 | struct list_head *_tmp; | 141 | struct list_head *_tmp; |
127 | /* May be called with or without RTNL lock held */ | 142 | |
128 | int islocked = rtnl_is_locked(); | 143 | rtnl_lock(); |
129 | if (!islocked) | ||
130 | rtnl_lock(); | ||
131 | list_for_each_safe(list_node, _tmp, &chnl_net_list) { | 144 | list_for_each_safe(list_node, _tmp, &chnl_net_list) { |
132 | dev = list_entry(list_node, struct chnl_net, list_field); | 145 | dev = list_entry(list_node, struct chnl_net, list_field); |
133 | if (dev->state == CAIF_SHUTDOWN) | 146 | if (dev->state == CAIF_SHUTDOWN) |
134 | dev_close(dev->netdev); | 147 | dev_close(dev->netdev); |
135 | } | 148 | } |
136 | if (!islocked) | 149 | rtnl_unlock(); |
137 | rtnl_unlock(); | ||
138 | } | 150 | } |
139 | static DECLARE_WORK(close_worker, close_work); | 151 | static DECLARE_WORK(close_worker, close_work); |
140 | 152 | ||
153 | static void chnl_hold(struct cflayer *lyr) | ||
154 | { | ||
155 | struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl); | ||
156 | dev_hold(priv->netdev); | ||
157 | } | ||
158 | |||
159 | static void chnl_put(struct cflayer *lyr) | ||
160 | { | ||
161 | struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl); | ||
162 | dev_put(priv->netdev); | ||
163 | } | ||
164 | |||
141 | static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, | 165 | static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, |
142 | int phyid) | 166 | int phyid) |
143 | { | 167 | { |
144 | struct chnl_net *priv = container_of(layr, struct chnl_net, chnl); | 168 | struct chnl_net *priv = container_of(layr, struct chnl_net, chnl); |
145 | pr_debug("CAIF: %s(): NET flowctrl func called flow: %s\n", | 169 | pr_debug("NET flowctrl func called flow: %s\n", |
146 | __func__, | ||
147 | flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" : | 170 | flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" : |
148 | flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" : | 171 | flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" : |
149 | flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" : | 172 | flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" : |
@@ -176,6 +199,7 @@ static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, | |||
176 | netif_wake_queue(priv->netdev); | 199 | netif_wake_queue(priv->netdev); |
177 | break; | 200 | break; |
178 | case CAIF_CTRLCMD_INIT_RSP: | 201 | case CAIF_CTRLCMD_INIT_RSP: |
202 | caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put); | ||
179 | priv->state = CAIF_CONNECTED; | 203 | priv->state = CAIF_CONNECTED; |
180 | priv->flowenabled = true; | 204 | priv->flowenabled = true; |
181 | netif_wake_queue(priv->netdev); | 205 | netif_wake_queue(priv->netdev); |
@@ -196,12 +220,12 @@ static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
196 | priv = netdev_priv(dev); | 220 | priv = netdev_priv(dev); |
197 | 221 | ||
198 | if (skb->len > priv->netdev->mtu) { | 222 | if (skb->len > priv->netdev->mtu) { |
199 | pr_warning("CAIF: %s(): Size of skb exceeded MTU\n", __func__); | 223 | pr_warn("Size of skb exceeded MTU\n"); |
200 | return -ENOSPC; | 224 | return -ENOSPC; |
201 | } | 225 | } |
202 | 226 | ||
203 | if (!priv->flowenabled) { | 227 | if (!priv->flowenabled) { |
204 | pr_debug("CAIF: %s(): dropping packets flow off\n", __func__); | 228 | pr_debug("dropping packets flow off\n"); |
205 | return NETDEV_TX_BUSY; | 229 | return NETDEV_TX_BUSY; |
206 | } | 230 | } |
207 | 231 | ||
@@ -237,27 +261,27 @@ static int chnl_net_open(struct net_device *dev) | |||
237 | ASSERT_RTNL(); | 261 | ASSERT_RTNL(); |
238 | priv = netdev_priv(dev); | 262 | priv = netdev_priv(dev); |
239 | if (!priv) { | 263 | if (!priv) { |
240 | pr_debug("CAIF: %s(): chnl_net_open: no priv\n", __func__); | 264 | pr_debug("chnl_net_open: no priv\n"); |
241 | return -ENODEV; | 265 | return -ENODEV; |
242 | } | 266 | } |
243 | 267 | ||
244 | if (priv->state != CAIF_CONNECTING) { | 268 | if (priv->state != CAIF_CONNECTING) { |
245 | priv->state = CAIF_CONNECTING; | 269 | priv->state = CAIF_CONNECTING; |
246 | result = caif_connect_client(&priv->conn_req, &priv->chnl, | 270 | result = caif_connect_client(dev_net(dev), &priv->conn_req, |
247 | &llifindex, &headroom, &tailroom); | 271 | &priv->chnl, &llifindex, |
272 | &headroom, &tailroom); | ||
248 | if (result != 0) { | 273 | if (result != 0) { |
249 | pr_debug("CAIF: %s(): err: " | 274 | pr_debug("err: " |
250 | "Unable to register and open device," | 275 | "Unable to register and open device," |
251 | " Err:%d\n", | 276 | " Err:%d\n", |
252 | __func__, | 277 | result); |
253 | result); | ||
254 | goto error; | 278 | goto error; |
255 | } | 279 | } |
256 | 280 | ||
257 | lldev = dev_get_by_index(dev_net(dev), llifindex); | 281 | lldev = dev_get_by_index(dev_net(dev), llifindex); |
258 | 282 | ||
259 | if (lldev == NULL) { | 283 | if (lldev == NULL) { |
260 | pr_debug("CAIF: %s(): no interface?\n", __func__); | 284 | pr_debug("no interface?\n"); |
261 | result = -ENODEV; | 285 | result = -ENODEV; |
262 | goto error; | 286 | goto error; |
263 | } | 287 | } |
@@ -279,9 +303,7 @@ static int chnl_net_open(struct net_device *dev) | |||
279 | dev_put(lldev); | 303 | dev_put(lldev); |
280 | 304 | ||
281 | if (mtu < 100) { | 305 | if (mtu < 100) { |
282 | pr_warning("CAIF: %s(): " | 306 | pr_warn("CAIF Interface MTU too small (%d)\n", mtu); |
283 | "CAIF Interface MTU too small (%d)\n", | ||
284 | __func__, mtu); | ||
285 | result = -ENODEV; | 307 | result = -ENODEV; |
286 | goto error; | 308 | goto error; |
287 | } | 309 | } |
@@ -296,33 +318,32 @@ static int chnl_net_open(struct net_device *dev) | |||
296 | rtnl_lock(); | 318 | rtnl_lock(); |
297 | 319 | ||
298 | if (result == -ERESTARTSYS) { | 320 | if (result == -ERESTARTSYS) { |
299 | pr_debug("CAIF: %s(): wait_event_interruptible" | 321 | pr_debug("wait_event_interruptible woken by a signal\n"); |
300 | " woken by a signal\n", __func__); | ||
301 | result = -ERESTARTSYS; | 322 | result = -ERESTARTSYS; |
302 | goto error; | 323 | goto error; |
303 | } | 324 | } |
304 | 325 | ||
305 | if (result == 0) { | 326 | if (result == 0) { |
306 | pr_debug("CAIF: %s(): connect timeout\n", __func__); | 327 | pr_debug("connect timeout\n"); |
307 | caif_disconnect_client(&priv->chnl); | 328 | caif_disconnect_client(dev_net(dev), &priv->chnl); |
308 | priv->state = CAIF_DISCONNECTED; | 329 | priv->state = CAIF_DISCONNECTED; |
309 | pr_debug("CAIF: %s(): state disconnected\n", __func__); | 330 | pr_debug("state disconnected\n"); |
310 | result = -ETIMEDOUT; | 331 | result = -ETIMEDOUT; |
311 | goto error; | 332 | goto error; |
312 | } | 333 | } |
313 | 334 | ||
314 | if (priv->state != CAIF_CONNECTED) { | 335 | if (priv->state != CAIF_CONNECTED) { |
315 | pr_debug("CAIF: %s(): connect failed\n", __func__); | 336 | pr_debug("connect failed\n"); |
316 | result = -ECONNREFUSED; | 337 | result = -ECONNREFUSED; |
317 | goto error; | 338 | goto error; |
318 | } | 339 | } |
319 | pr_debug("CAIF: %s(): CAIF Netdevice connected\n", __func__); | 340 | pr_debug("CAIF Netdevice connected\n"); |
320 | return 0; | 341 | return 0; |
321 | 342 | ||
322 | error: | 343 | error: |
323 | caif_disconnect_client(&priv->chnl); | 344 | caif_disconnect_client(dev_net(dev), &priv->chnl); |
324 | priv->state = CAIF_DISCONNECTED; | 345 | priv->state = CAIF_DISCONNECTED; |
325 | pr_debug("CAIF: %s(): state disconnected\n", __func__); | 346 | pr_debug("state disconnected\n"); |
326 | return result; | 347 | return result; |
327 | 348 | ||
328 | } | 349 | } |
@@ -334,7 +355,7 @@ static int chnl_net_stop(struct net_device *dev) | |||
334 | ASSERT_RTNL(); | 355 | ASSERT_RTNL(); |
335 | priv = netdev_priv(dev); | 356 | priv = netdev_priv(dev); |
336 | priv->state = CAIF_DISCONNECTED; | 357 | priv->state = CAIF_DISCONNECTED; |
337 | caif_disconnect_client(&priv->chnl); | 358 | caif_disconnect_client(dev_net(dev), &priv->chnl); |
338 | return 0; | 359 | return 0; |
339 | } | 360 | } |
340 | 361 | ||
@@ -363,11 +384,18 @@ static const struct net_device_ops netdev_ops = { | |||
363 | .ndo_start_xmit = chnl_net_start_xmit, | 384 | .ndo_start_xmit = chnl_net_start_xmit, |
364 | }; | 385 | }; |
365 | 386 | ||
387 | static void chnl_net_destructor(struct net_device *dev) | ||
388 | { | ||
389 | struct chnl_net *priv = netdev_priv(dev); | ||
390 | caif_free_client(&priv->chnl); | ||
391 | free_netdev(dev); | ||
392 | } | ||
393 | |||
366 | static void ipcaif_net_setup(struct net_device *dev) | 394 | static void ipcaif_net_setup(struct net_device *dev) |
367 | { | 395 | { |
368 | struct chnl_net *priv; | 396 | struct chnl_net *priv; |
369 | dev->netdev_ops = &netdev_ops; | 397 | dev->netdev_ops = &netdev_ops; |
370 | dev->destructor = free_netdev; | 398 | dev->destructor = chnl_net_destructor; |
371 | dev->flags |= IFF_NOARP; | 399 | dev->flags |= IFF_NOARP; |
372 | dev->flags |= IFF_POINTOPOINT; | 400 | dev->flags |= IFF_POINTOPOINT; |
373 | dev->mtu = GPRS_PDP_MTU; | 401 | dev->mtu = GPRS_PDP_MTU; |
@@ -381,12 +409,10 @@ static void ipcaif_net_setup(struct net_device *dev) | |||
381 | priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW; | 409 | priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW; |
382 | priv->conn_req.priority = CAIF_PRIO_LOW; | 410 | priv->conn_req.priority = CAIF_PRIO_LOW; |
383 | /* Insert illegal value */ | 411 | /* Insert illegal value */ |
384 | priv->conn_req.sockaddr.u.dgm.connection_id = -1; | 412 | priv->conn_req.sockaddr.u.dgm.connection_id = 0; |
385 | priv->flowenabled = false; | 413 | priv->flowenabled = false; |
386 | 414 | ||
387 | ASSERT_RTNL(); | ||
388 | init_waitqueue_head(&priv->netmgmt_wq); | 415 | init_waitqueue_head(&priv->netmgmt_wq); |
389 | list_add(&priv->list_field, &chnl_net_list); | ||
390 | } | 416 | } |
391 | 417 | ||
392 | 418 | ||
@@ -413,7 +439,7 @@ static void caif_netlink_parms(struct nlattr *data[], | |||
413 | struct caif_connect_request *conn_req) | 439 | struct caif_connect_request *conn_req) |
414 | { | 440 | { |
415 | if (!data) { | 441 | if (!data) { |
416 | pr_warning("CAIF: %s: no params data found\n", __func__); | 442 | pr_warn("no params data found\n"); |
417 | return; | 443 | return; |
418 | } | 444 | } |
419 | if (data[IFLA_CAIF_IPV4_CONNID]) | 445 | if (data[IFLA_CAIF_IPV4_CONNID]) |
@@ -442,8 +468,13 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev, | |||
442 | 468 | ||
443 | ret = register_netdevice(dev); | 469 | ret = register_netdevice(dev); |
444 | if (ret) | 470 | if (ret) |
445 | pr_warning("CAIF: %s(): device rtml registration failed\n", | 471 | pr_warn("device rtml registration failed\n"); |
446 | __func__); | 472 | else |
473 | list_add(&caifdev->list_field, &chnl_net_list); | ||
474 | |||
475 | /* Take ifindex as connection-id if null */ | ||
476 | if (caifdev->conn_req.sockaddr.u.dgm.connection_id == 0) | ||
477 | caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex; | ||
447 | return ret; | 478 | return ret; |
448 | } | 479 | } |
449 | 480 | ||