Commit a2805dca authored by Pavel Skripkin's avatar Pavel Skripkin Committed by David S. Miller

net: caif: add proper error handling

caif_enroll_dev() can fail in some cases. Ingnoring
these cases can lead to memory leak due to not assigning
link_support pointer to anywhere.

Fixes: 7c18d220 ("caif: Restructure how link caif link layer enroll")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarPavel Skripkin <paskripkin@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bce130e7
...@@ -119,7 +119,7 @@ void caif_free_client(struct cflayer *adap_layer); ...@@ -119,7 +119,7 @@ void caif_free_client(struct cflayer *adap_layer);
* The link_support layer is used to add any Link Layer specific * The link_support layer is used to add any Link Layer specific
* framing. * framing.
*/ */
void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev, int caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
struct cflayer *link_support, int head_room, struct cflayer *link_support, int head_room,
struct cflayer **layer, int (**rcv_func)( struct cflayer **layer, int (**rcv_func)(
struct sk_buff *, struct net_device *, struct sk_buff *, struct net_device *,
......
...@@ -62,7 +62,7 @@ void cfcnfg_remove(struct cfcnfg *cfg); ...@@ -62,7 +62,7 @@ void cfcnfg_remove(struct cfcnfg *cfg);
* @fcs: Specify if checksum is used in CAIF Framing Layer. * @fcs: Specify if checksum is used in CAIF Framing Layer.
* @head_room: Head space needed by link specific protocol. * @head_room: Head space needed by link specific protocol.
*/ */
void int
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
struct net_device *dev, struct cflayer *phy_layer, struct net_device *dev, struct cflayer *phy_layer,
enum cfcnfg_phy_preference pref, enum cfcnfg_phy_preference pref,
......
...@@ -308,7 +308,7 @@ static void dev_flowctrl(struct net_device *dev, int on) ...@@ -308,7 +308,7 @@ static void dev_flowctrl(struct net_device *dev, int on)
caifd_put(caifd); caifd_put(caifd);
} }
void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev, int caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
struct cflayer *link_support, int head_room, struct cflayer *link_support, int head_room,
struct cflayer **layer, struct cflayer **layer,
int (**rcv_func)(struct sk_buff *, struct net_device *, int (**rcv_func)(struct sk_buff *, struct net_device *,
...@@ -319,11 +319,12 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev, ...@@ -319,11 +319,12 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
enum cfcnfg_phy_preference pref; enum cfcnfg_phy_preference pref;
struct cfcnfg *cfg = get_cfcnfg(dev_net(dev)); struct cfcnfg *cfg = get_cfcnfg(dev_net(dev));
struct caif_device_entry_list *caifdevs; struct caif_device_entry_list *caifdevs;
int res;
caifdevs = caif_device_list(dev_net(dev)); caifdevs = caif_device_list(dev_net(dev));
caifd = caif_device_alloc(dev); caifd = caif_device_alloc(dev);
if (!caifd) if (!caifd)
return; return -ENOMEM;
*layer = &caifd->layer; *layer = &caifd->layer;
spin_lock_init(&caifd->flow_lock); spin_lock_init(&caifd->flow_lock);
...@@ -344,7 +345,7 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev, ...@@ -344,7 +345,7 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
strlcpy(caifd->layer.name, dev->name, strlcpy(caifd->layer.name, dev->name,
sizeof(caifd->layer.name)); sizeof(caifd->layer.name));
caifd->layer.transmit = transmit; caifd->layer.transmit = transmit;
cfcnfg_add_phy_layer(cfg, res = cfcnfg_add_phy_layer(cfg,
dev, dev,
&caifd->layer, &caifd->layer,
pref, pref,
...@@ -354,6 +355,7 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev, ...@@ -354,6 +355,7 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
mutex_unlock(&caifdevs->lock); mutex_unlock(&caifdevs->lock);
if (rcv_func) if (rcv_func)
*rcv_func = receive; *rcv_func = receive;
return res;
} }
EXPORT_SYMBOL(caif_enroll_dev); EXPORT_SYMBOL(caif_enroll_dev);
......
...@@ -450,7 +450,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, ...@@ -450,7 +450,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
rcu_read_unlock(); rcu_read_unlock();
} }
void int
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
struct net_device *dev, struct cflayer *phy_layer, struct net_device *dev, struct cflayer *phy_layer,
enum cfcnfg_phy_preference pref, enum cfcnfg_phy_preference pref,
...@@ -459,7 +459,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, ...@@ -459,7 +459,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
{ {
struct cflayer *frml; struct cflayer *frml;
struct cfcnfg_phyinfo *phyinfo = NULL; struct cfcnfg_phyinfo *phyinfo = NULL;
int i; int i, res = 0;
u8 phyid; u8 phyid;
mutex_lock(&cnfg->lock); mutex_lock(&cnfg->lock);
...@@ -473,12 +473,15 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, ...@@ -473,12 +473,15 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
goto got_phyid; goto got_phyid;
} }
pr_warn("Too many CAIF Link Layers (max 6)\n"); pr_warn("Too many CAIF Link Layers (max 6)\n");
res = -EEXIST;
goto out; goto out;
got_phyid: got_phyid:
phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC); phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
if (!phyinfo) if (!phyinfo) {
res = -ENOMEM;
goto out_err; goto out_err;
}
phy_layer->id = phyid; phy_layer->id = phyid;
phyinfo->pref = pref; phyinfo->pref = pref;
...@@ -492,8 +495,10 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, ...@@ -492,8 +495,10 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
frml = cffrml_create(phyid, fcs); frml = cffrml_create(phyid, fcs);
if (!frml) if (!frml) {
res = -ENOMEM;
goto out_err; goto out_err;
}
phyinfo->frm_layer = frml; phyinfo->frm_layer = frml;
layer_set_up(frml, cnfg->mux); layer_set_up(frml, cnfg->mux);
...@@ -511,11 +516,12 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, ...@@ -511,11 +516,12 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
list_add_rcu(&phyinfo->node, &cnfg->phys); list_add_rcu(&phyinfo->node, &cnfg->phys);
out: out:
mutex_unlock(&cnfg->lock); mutex_unlock(&cnfg->lock);
return; return res;
out_err: out_err:
kfree(phyinfo); kfree(phyinfo);
mutex_unlock(&cnfg->lock); mutex_unlock(&cnfg->lock);
return res;
} }
EXPORT_SYMBOL(cfcnfg_add_phy_layer); EXPORT_SYMBOL(cfcnfg_add_phy_layer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment