#include <net/caif/caif_layer.h>
#include <net/caif/cfcnfg.h>
+#include <net/caif/caif_device.h>
#include <linux/caif/caif_socket.h>
#include <linux/if.h>
#include <linux/net.h>
*/
void caif_free_client(struct cflayer *adap_layer);
+/**
+ * struct caif_enroll_dev - Enroll a net-device as a CAIF Link layer
+ * @dev: Network device to enroll.
+ * @caifdev: Configuration information from CAIF Link Layer
+ * @link_support: Link layer support layer
+ * @head_room: Head room needed by link support layer
+ * @layer: Lowest layer in CAIF stack
+ * @rcv_fun: Receive function for CAIF stack.
+ *
+ * This function enroll a CAIF link layer into CAIF Stack and
+ * expects the interface to be able to handle CAIF payload.
+ * The link_support layer is used to add any Link Layer specific
+ * framing.
+ */
+void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
+ struct cflayer *link_support, int head_room,
+ struct cflayer **layer, int (**rcv_func)(
+ struct sk_buff *, struct net_device *,
+ struct packet_type *, struct net_device *));
+
#endif /* CAIF_DEV_H_ */
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>
+#include <net/caif/cfserl.h>
MODULE_LICENSE("GPL");
struct caif_net *caifn;
BUG_ON(!net);
caifn = net_generic(net, caif_net_id);
- BUG_ON(!caifn);
+ if (!caifn)
+ return NULL;
return caifn->cfg;
}
EXPORT_SYMBOL(get_cfcnfg);
struct caif_net *caifn;
BUG_ON(!net);
caifn = net_generic(net, caif_net_id);
- BUG_ON(!caifn);
+ if (!caifn)
+ return NULL;
return &caifn->caifdevs;
}
struct caif_device_entry *caifd;
caifdevs = caif_device_list(dev_net(dev));
- BUG_ON(!caifdevs);
+ if (!caifdevs)
+ return NULL;
caifd = kzalloc(sizeof(*caifd), GFP_KERNEL);
if (!caifd)
struct caif_device_entry_list *caifdevs =
caif_device_list(dev_net(dev));
struct caif_device_entry *caifd;
- BUG_ON(!caifdevs);
+ if (!caifdevs)
+ return NULL;
+
list_for_each_entry_rcu(caifd, &caifdevs->list, list) {
if (caifd->netdev == dev)
return caifd;
skb = cfpkt_tonative(pkt);
skb->dev = caifd->netdev;
+ skb_reset_network_header(skb);
+ skb->protocol = htons(ETH_P_CAIF);
err = dev_queue_xmit(skb);
if (err > 0)
/* Release reference to stack upwards */
caifd_put(caifd);
- return 0;
+
+ if (err != 0)
+ err = NET_RX_DROP;
+ return err;
}
static struct packet_type caif_packet_type __read_mostly = {
caifd_put(caifd);
}
+void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
+ struct cflayer *link_support, int head_room,
+ struct cflayer **layer, int (**rcv_func)(
+ struct sk_buff *, struct net_device *,
+ struct packet_type *, struct net_device *))
+{
+ struct caif_device_entry *caifd;
+ enum cfcnfg_phy_preference pref;
+ struct cfcnfg *cfg = get_cfcnfg(dev_net(dev));
+ struct caif_device_entry_list *caifdevs;
+
+ caifdevs = caif_device_list(dev_net(dev));
+ if (!cfg || !caifdevs)
+ return;
+ caifd = caif_device_alloc(dev);
+ if (!caifd)
+ return;
+ *layer = &caifd->layer;
+
+ switch (caifdev->link_select) {
+ case CAIF_LINK_HIGH_BANDW:
+ pref = CFPHYPREF_HIGH_BW;
+ break;
+ case CAIF_LINK_LOW_LATENCY:
+ pref = CFPHYPREF_LOW_LAT;
+ break;
+ default:
+ pref = CFPHYPREF_HIGH_BW;
+ break;
+ }
+ mutex_lock(&caifdevs->lock);
+ list_add_rcu(&caifd->list, &caifdevs->list);
+
+ strncpy(caifd->layer.name, dev->name,
+ sizeof(caifd->layer.name) - 1);
+ caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
+ caifd->layer.transmit = transmit;
+ cfcnfg_add_phy_layer(cfg,
+ dev,
+ &caifd->layer,
+ pref,
+ link_support,
+ caifdev->use_fcs,
+ head_room);
+ mutex_unlock(&caifdevs->lock);
+ if (rcv_func)
+ *rcv_func = receive;
+}
+
/* notify Caif of device events */
static int caif_device_notify(struct notifier_block *me, unsigned long what,
void *arg)
struct net_device *dev = arg;
struct caif_device_entry *caifd = NULL;
struct caif_dev_common *caifdev;
- enum cfcnfg_phy_preference pref;
- enum cfcnfg_phy_type phy_type;
struct cfcnfg *cfg;
+ struct cflayer *layer, *link_support;
+ int head_room = 0;
struct caif_device_entry_list *caifdevs;
- if (dev->type != ARPHRD_CAIF)
- return 0;
-
cfg = get_cfcnfg(dev_net(dev));
- if (cfg == NULL)
+ caifdevs = caif_device_list(dev_net(dev));
+ if (!cfg || !caifdevs)
return 0;
- caifdevs = caif_device_list(dev_net(dev));
+ caifd = caif_get(dev);
+ if (caifd == NULL && dev->type != ARPHRD_CAIF)
+ return 0;
switch (what) {
case NETDEV_REGISTER:
- caifd = caif_device_alloc(dev);
- if (!caifd)
- return 0;
+ if (caifd != NULL)
+ break;
caifdev = netdev_priv(dev);
- caifdev->flowctrl = dev_flowctrl;
- caifd->layer.transmit = transmit;
-
- if (caifdev->use_frag)
- phy_type = CFPHYTYPE_FRAG;
- else
- phy_type = CFPHYTYPE_CAIF;
-
- switch (caifdev->link_select) {
- case CAIF_LINK_HIGH_BANDW:
- pref = CFPHYPREF_HIGH_BW;
- break;
- case CAIF_LINK_LOW_LATENCY:
- pref = CFPHYPREF_LOW_LAT;
- break;
- default:
- pref = CFPHYPREF_HIGH_BW;
- break;
+ link_support = NULL;
+ if (caifdev->use_frag) {
+ head_room = 1;
+ link_support = cfserl_create(dev->ifindex,
+ CFPHYTYPE_FRAG, caifdev->use_stx);
+ if (!link_support) {
+ pr_warn("Out of memory\n");
+ break;
+ }
}
- strncpy(caifd->layer.name, dev->name,
- sizeof(caifd->layer.name) - 1);
- caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
-
- mutex_lock(&caifdevs->lock);
- list_add_rcu(&caifd->list, &caifdevs->list);
-
- cfcnfg_add_phy_layer(cfg,
- phy_type,
- dev,
- &caifd->layer,
- pref,
- caifdev->use_fcs,
- caifdev->use_stx);
- mutex_unlock(&caifdevs->lock);
+ caif_enroll_dev(dev, caifdev, link_support, head_room,
+ &layer, NULL);
+ caifdev->flowctrl = dev_flowctrl;
break;
case NETDEV_UP:
struct caif_device_entry *caifd, *tmp;
struct caif_device_entry_list *caifdevs =
caif_device_list(net);
- struct cfcnfg *cfg;
+ struct cfcnfg *cfg = get_cfcnfg(net);
+
+ if (!cfg || !caifdevs)
+ return;
rtnl_lock();
mutex_lock(&caifdevs->lock);
- cfg = get_cfcnfg(net);
- if (cfg == NULL) {
- mutex_unlock(&caifdevs->lock);
- return;
- }
-
list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) {
int i = 0;
list_del_rcu(&caifd->list);
/* Interface index */
int ifindex;
- /* Use Start of frame extension */
- bool use_stx;
+ /* Protocol head room added for CAIF link layer */
+ int head_room;
/* Use Start of frame checksum */
bool use_fcs;
if (channel_id != 0) {
struct cflayer *servl;
servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
+ cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
if (servl != NULL)
layer_set_up(servl, NULL);
} else
pr_debug("nothing to disconnect\n");
- cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
/* Do RCU sync before initiating cleanup */
synchronize_rcu();
*ifindex = phy->ifindex;
*proto_tail = 2;
- *proto_head =
-
- protohead[param.linktype] + (phy->use_stx ? 1 : 0);
+ *proto_head = protohead[param.linktype] + phy->head_room;
rcu_read_unlock();
}
void
-cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
+cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
struct net_device *dev, struct cflayer *phy_layer,
enum cfcnfg_phy_preference pref,
- bool fcs, bool stx)
+ struct cflayer *link_support,
+ bool fcs, int head_room)
{
struct cflayer *frml;
- struct cflayer *phy_driver = NULL;
struct cfcnfg_phyinfo *phyinfo = NULL;
int i;
u8 phyid;
goto got_phyid;
}
pr_warn("Too many CAIF Link Layers (max 6)\n");
- goto out_err;
+ goto out;
got_phyid:
phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
if (!phyinfo)
goto out_err;
- switch (phy_type) {
- case CFPHYTYPE_FRAG:
- phy_driver =
- cfserl_create(CFPHYTYPE_FRAG, phyid, stx);
- if (!phy_driver)
- goto out_err;
- break;
- case CFPHYTYPE_CAIF:
- phy_driver = NULL;
- break;
- default:
- goto out_err;
- }
phy_layer->id = phyid;
phyinfo->pref = pref;
phyinfo->id = phyid;
phyinfo->dev_info.dev = dev;
phyinfo->phy_layer = phy_layer;
phyinfo->ifindex = dev->ifindex;
- phyinfo->use_stx = stx;
+ phyinfo->head_room = head_room;
phyinfo->use_fcs = fcs;
frml = cffrml_create(phyid, fcs);
phyinfo->frm_layer = frml;
layer_set_up(frml, cnfg->mux);
- if (phy_driver != NULL) {
- phy_driver->id = phyid;
- layer_set_dn(frml, phy_driver);
- layer_set_up(phy_driver, frml);
- layer_set_dn(phy_driver, phy_layer);
- layer_set_up(phy_layer, phy_driver);
+ if (link_support != NULL) {
+ link_support->id = phyid;
+ layer_set_dn(frml, link_support);
+ layer_set_up(link_support, frml);
+ layer_set_dn(link_support, phy_layer);
+ layer_set_up(phy_layer, link_support);
} else {
layer_set_dn(frml, phy_layer);
layer_set_up(phy_layer, frml);
}
list_add_rcu(&phyinfo->node, &cnfg->phys);
+out:
mutex_unlock(&cnfg->lock);
return;
out_err:
- kfree(phy_driver);
kfree(phyinfo);
mutex_unlock(&cnfg->lock);
}