net: phonet: Modifications for RMC PegaPCI.
Raj Jayaraman [Mon, 17 Sep 2012 18:19:54 +0000 (11:19 -0700)]
* As submitted by RMC for modem support *

Bug 1054808

Change-Id: I6674df1870dea09e3a1b6035d2d8218e2f56de3b
Signed-off-by: Raj Jayaraman <rjayaraman@nvidia.com>
Reviewed-on: http://git-master/r/160031
(cherry picked from commit 60564998c44336e29d653e7d10a20555f0a5703b)
Reviewed-on: http://git-master/r/162291
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: WK Tsai <wtsai@nvidia.com>
Reviewed-by: Steve Lin <stlin@nvidia.com>

include/linux/if_arp.h
include/linux/phonet.h
include/net/phonet/phonet.h
net/phonet/af_phonet.c
net/phonet/pn_dev.c
net/phonet/pn_netlink.c
net/phonet/socket.c

index 6d722f4..0c3ec71 100644 (file)
@@ -91,6 +91,7 @@
 #define ARPHRD_PHONET  820             /* PhoNet media type            */
 #define ARPHRD_PHONET_PIPE 821         /* PhoNet pipe header           */
 #define ARPHRD_CAIF    822             /* CAIF media type              */
+#define ARPHRD_MHI     823             /* Modem-Host IF                */
 
 #define ARPHRD_VOID      0xFFFF        /* Void type, nothing is known */
 #define ARPHRD_NONE      0xFFFE        /* zero header length */
index f48bfc8..fb80c25 100644 (file)
 #include <linux/types.h>
 #include <linux/socket.h>
 
+/* Phonet media types */
+#define PN_MEDIA_ROUTING       0x00
+#define PN_MEDIA_USB           0x1B
+#define PN_MEDIA_DEFAULT       0x25
+#define PN_MEDIA_MODEM_HOST_IF  0x26
+
 /* Automatic protocol selection */
 #define PN_PROTO_TRANSPORT     0
 /* Phonet datagram socket */
@@ -44,6 +50,9 @@
 #define PNADDR_BROADCAST       0xFC
 #define PNPORT_RESOURCE_ROUTING        0
 
+/* define object for multicast */
+#define PNOBJECT_MULTICAST 0x20
+
 /* Values for PNPIPE_ENCAP option */
 #define PNPIPE_ENCAP_NONE      0
 #define PNPIPE_ENCAP_IP                1
@@ -53,6 +62,8 @@
 #define SIOCPNENABLEPIPE       (SIOCPROTOPRIVATE + 13)
 #define SIOCPNADDRESOURCE      (SIOCPROTOPRIVATE + 14)
 #define SIOCPNDELRESOURCE      (SIOCPROTOPRIVATE + 15)
+#define SIOCCONFIGTYPE         (SIOCPROTOPRIVATE + 1)
+#define SIOCCONFIGSUBTYPE      (SIOCPROTOPRIVATE + 2)
 
 /* Phonet protocol header */
 struct phonethdr {
index 68e5097..f23fcf1 100644 (file)
@@ -38,6 +38,8 @@ struct pn_sock {
        u16             sobject;
        u16             dobject;
        u8              resource;
+       u8              resource_type;
+       u8              resource_subtype;
 };
 
 static inline struct pn_sock *pn_sk(struct sock *sk)
@@ -48,6 +50,8 @@ static inline struct pn_sock *pn_sk(struct sock *sk)
 extern const struct proto_ops phonet_dgram_ops;
 
 void pn_sock_init(void);
+struct sock *pn_find_sock_by_sa_and_skb(struct net *net,
+               const struct sockaddr_pn *spn, struct sk_buff *skb);
 struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *sa);
 void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb);
 void phonet_get_local_port_range(int *min, int *max);
index d65f699..be0c3d4 100644 (file)
@@ -68,8 +68,10 @@ static int pn_socket_create(struct net *net, struct socket *sock, int protocol,
        struct phonet_protocol *pnp;
        int err;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
+/*PATCH
+ *     if (!capable(CAP_SYS_ADMIN))
+ *     return -EPERM;
+ */
 
        if (protocol == 0) {
                /* Default protocol selection */
@@ -112,6 +114,8 @@ static int pn_socket_create(struct net *net, struct socket *sock, int protocol,
        pn->sobject = 0;
        pn->dobject = 0;
        pn->resource = 0;
+/*!*/  pn->resource_type = 0;
+/*!*/  pn->resource_subtype = 0;
        sk->sk_prot->init(sk);
        err = 0;
 
@@ -210,6 +214,7 @@ static int pn_send(struct sk_buff *skb, struct net_device *dev,
 
        return err;
 drop:
+       printk(KERN_DEBUG "pn_send DROP\n");
        kfree_skb(skb);
        return err;
 }
@@ -287,6 +292,7 @@ int pn_skb_send(struct sock *sk, struct sk_buff *skb,
        return err;
 
 drop:
+       printk(KERN_DEBUG "pn_skb_send DROP\n");
        kfree_skb(skb);
        if (dev)
                dev_put(dev);
@@ -393,6 +399,12 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
 
        pn_skb_get_dst_sockaddr(skb, &sa);
 
+       /* check if this is multicasted */
+       if (pn_sockaddr_get_object(&sa) == PNOBJECT_MULTICAST) {
+               pn_deliver_sock_broadcast(net, skb);
+               goto out;
+       }
+
        /* check if this is broadcasted */
        if (pn_sockaddr_get_addr(&sa) == PNADDR_BROADCAST) {
                pn_deliver_sock_broadcast(net, skb);
@@ -402,14 +414,17 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
        /* resource routing */
        if (pn_sockaddr_get_object(&sa) == 0) {
                struct sock *sk = pn_find_sock_by_res(net, sa.spn_resource);
-               if (sk)
+               if (sk) {
+                       printk(KERN_DEBUG "phonet new resource routing!\n");
                        return sk_receive_skb(sk, skb, 0);
+               }
        }
 
        /* check if we are the destination */
        if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
                /* Phonet packet input */
-               struct sock *sk = pn_find_sock_by_sa(net, &sa);
+/*!*/          struct sock *sk = pn_find_sock_by_sa_and_skb(net, &sa, skb);
+               /*struct sock *sk = pn_find_sock_by_sa(net, &sa);*/
 
                if (sk)
                        return sk_receive_skb(sk, skb, 0);
@@ -454,6 +469,7 @@ out_dev:
 
 out:
        kfree_skb(skb);
+       printk(KERN_DEBUG "phonet_rcv Drop message!\n");
        return NET_RX_DROP;
 }
 
index bf5cf69..b155ca0 100644 (file)
@@ -298,7 +298,7 @@ static int phonet_device_notify(struct notifier_block *me, unsigned long what,
 
        switch (what) {
        case NETDEV_REGISTER:
-               if (dev->type == ARPHRD_PHONET)
+               if (dev->type == ARPHRD_PHONET || dev->type == ARPHRD_MHI)
                        phonet_device_autoconf(dev);
                break;
        case NETDEV_UNREGISTER:
index d61f676..8aec4cb 100644 (file)
@@ -70,9 +70,6 @@ static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
        int err;
        u8 pnaddr;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        ASSERT_RTNL();
 
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_phonet_policy);
@@ -228,9 +225,6 @@ static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
        int err;
        u8 dst;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        ASSERT_RTNL();
 
        err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_phonet_policy);
index 4c7eff3..e25f0c2 100644 (file)
@@ -74,6 +74,94 @@ static struct hlist_head *pn_hash_list(u16 obj)
  * Find address based on socket address, match only certain fields.
  * Also grab sock if it was found. Remember to sock_put it later.
  */
+struct sock *pn_find_sock_by_sa_and_skb(struct net *net,
+                       const struct sockaddr_pn *spn, struct sk_buff *skb)
+{
+       struct hlist_node *node;
+       struct sock *sknode;
+       struct sock *rval = NULL;
+       u16 obj = pn_sockaddr_get_object(spn);
+       u8 res = spn->spn_resource;
+       struct hlist_head *hlist = pnsocks.hlist;
+       unsigned h;
+       u8 type;
+       u8 subtype;
+
+       rcu_read_lock();
+
+       for (h = 0; h < PN_HASHSIZE; h++) {
+               sk_for_each_rcu(sknode, node, hlist) {
+                       struct pn_sock *pn = pn_sk(sknode);
+                       BUG_ON(!pn->sobject); /* unbound socket */
+                       if (!net_eq(sock_net(sknode), net))
+                               continue;
+
+                       if ((PN_PREFIX == pn->resource) && (PN_PREFIX == res)) {
+                               if (skb_shinfo(skb)->nr_frags) {
+                                       struct page *msg_page;
+                                       u8 *msg;
+                                       skb_frag_t *msg_frag = &skb_shinfo(skb)
+                                                               ->frags[0];
+
+                                       msg_page = skb_frag_page(msg_frag);
+                                       msg = page_address(msg_page);
+
+                                       type = msg[msg_frag->page_offset+2];
+                                       subtype = msg[msg_frag->page_offset+3];
+
+                               } else {
+                                       type = *(skb->data + 2);
+                                       subtype = *(skb->data + 3);
+                               }
+
+                               if (type != pn->resource_type)
+                                       continue;
+
+                               if (subtype != pn->resource_subtype) {
+                                       /* printk("phonet resource subtype
+                                                don't match! type %d,
+                                               subtype %d pn->resource_subtype
+                                                %d\n", type, subtype,
+                                               pn->resource_subtype); */
+                                       continue;
+                               }
+                               /* printk("phonet resource match! type %d,
+                                        subtype %d\n", type, subtype); */
+                       }
+
+                       /* If port is zero, look up by resource */
+                       if (pn_port(obj)) {
+                               /* Look up socket by port */
+                               if (pn_port(pn->sobject) != pn_port(obj))
+                                       continue;
+                       } else {
+
+                               /* If port is zero, look up by resource */
+                               if (pn->resource != res)
+                                       continue;
+                       }
+
+                       if (pn_addr(pn->sobject) &&
+                           pn_addr(pn->sobject) != pn_addr(obj))
+                               continue;
+
+                       rval = sknode;
+                       sock_hold(sknode);
+                       goto out;
+               }
+               hlist++;
+       }
+
+out:
+       rcu_read_unlock();
+
+       return rval;
+}
+
+/*
+Find address based on socket address, match only certain fields.
+Also grab sock if it was found. Remember to sock_put it later.
+*/
 struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
 {
        struct hlist_node *node;
@@ -371,6 +459,33 @@ static int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
        struct sock *sk = sock->sk;
        struct pn_sock *pn = pn_sk(sk);
 
+       printk(KERN_DEBUG "pn_socket_ioctl with %s\n",
+               (cmd == SIOCCONFIGTYPE) ? "SIOCCONFIGTYPE" :
+               (cmd == SIOCCONFIGSUBTYPE) ? "SIOCCONFIGSUBTYPE" : "OTHER");
+
+       if (cmd == SIOCCONFIGTYPE) {
+               u16 type;
+               if (get_user(type, (__u16 __user *)arg))
+                       return -EFAULT;
+
+               printk(KERN_DEBUG "Phonet register resource type %d on %x\n",
+                                        type, pn);
+               pn->resource_type = type;
+               return 0;
+       }
+
+       if (cmd == SIOCCONFIGSUBTYPE) {
+               u16 subtype;
+
+               if (get_user(subtype, (__u16 __user *)arg))
+                       return -EFAULT;
+
+               pn->resource_subtype = subtype;
+               /* printk(KERN_DEBUG "Phonet register resource subtype %d on %x
+                                       \n", subtype, pn); */
+               return 0;
+       }
+
        if (cmd == SIOCPNGETOBJECT) {
                struct net_device *dev;
                u16 handle;