caif: Restructure how link caif link layer enroll
authorsjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com>
Wed, 30 Nov 2011 09:22:47 +0000 (09:22 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 1 Dec 2011 04:30:48 +0000 (23:30 -0500)
Enrolling CAIF link layers are refactored.

Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/caif/caif_dev.h
include/net/caif/cfcnfg.h
net/caif/caif_dev.c
net/caif/cfcnfg.c

index c011281d92c08d7b6d8189fc77ac887da3b620d9..ef2dd9438bb1124fe6426fea3769ec1f78429633 100644 (file)
@@ -9,6 +9,7 @@
 
 #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>
@@ -104,4 +105,24 @@ void caif_client_register_refcnt(struct cflayer *adapt_layer,
  */
 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_ */
index 3e93a4a4b677dfc811a9d91d954bf290be8e0964..a421723e986f710b64a6782763f366cbd4a57501 100644 (file)
@@ -72,15 +72,16 @@ void cfcnfg_remove(struct cfcnfg *cfg);
  * @phy_layer: Specify the physical layer. The transmit function
  *             MUST be set in the structure.
  * @pref:      The phy (link layer) preference.
+ * @link_support: Protocol implementation for link layer specific protocol.
  * @fcs:       Specify if checksum is used in CAIF Framing Layer.
- * @stx:       Specify if Start Of Frame eXtention is used.
+ * @head_room: Head space needed by link specific protocol.
  */
-
 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);
 
 /**
  * cfcnfg_del_phy_layer - Deletes an phy layer from the CAIF stack.
index f1fa1f6e658d4dc84ca6eea2abceb6be6d3e8283..70034c01782518834f2e6168849727f982c5ca86 100644 (file)
@@ -24,6 +24,7 @@
 #include <net/caif/caif_layer.h>
 #include <net/caif/cfpkt.h>
 #include <net/caif/cfcnfg.h>
+#include <net/caif/cfserl.h>
 
 MODULE_LICENSE("GPL");
 
@@ -53,7 +54,8 @@ struct cfcnfg *get_cfcnfg(struct net *net)
        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);
@@ -63,7 +65,8 @@ static struct caif_device_entry_list *caif_device_list(struct net *net)
        struct caif_net *caifn;
        BUG_ON(!net);
        caifn = net_generic(net, caif_net_id);
-       BUG_ON(!caifn);
+       if (!caifn)
+               return NULL;
        return &caifn->caifdevs;
 }
 
@@ -92,7 +95,8 @@ static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
        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)
@@ -112,7 +116,9 @@ static struct caif_device_entry *caif_get(struct net_device *dev)
        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;
@@ -129,6 +135,8 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt)
 
        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)
@@ -172,7 +180,10 @@ static int receive(struct sk_buff *skb, struct net_device *dev,
 
        /* 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 = {
@@ -203,6 +214,55 @@ static void dev_flowctrl(struct net_device *dev, int on)
        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)
@@ -210,62 +270,40 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
        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:
@@ -371,17 +409,14 @@ static void caif_exit_net(struct net *net)
        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);
index 00523ecc4ced75ebaa1059c1eb3e0a324cae182e..598aafb4cb5169e799148ffd6b33d351b702be7d 100644 (file)
@@ -45,8 +45,8 @@ struct cfcnfg_phyinfo {
        /* 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;
@@ -187,11 +187,11 @@ int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
        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();
@@ -350,9 +350,7 @@ int caif_connect_client(struct net *net, struct caif_connect_request *conn_req,
 
        *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();
 
@@ -460,13 +458,13 @@ 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;
@@ -482,26 +480,13 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
                        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;
@@ -509,7 +494,7 @@ got_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);
@@ -519,23 +504,23 @@ got_phyid:
        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);
 }