]> err.no Git - linux-2.6/blobdiff - net/tipc/port.c
tipc: Fix skb_under_panic when configuring TIPC without privileges
[linux-2.6] / net / tipc / port.c
index 76088153524cf2da2d22f20a4ccdef77643a15be..757de38fe6afcf84bf69d3d98114fe0bdfea9a34 100644 (file)
@@ -211,15 +211,18 @@ exit:
 }
 
 /**
- * tipc_createport_raw - create a native TIPC port
+ * tipc_createport_raw - create a generic TIPC port
  *
- * Returns local port reference
+ * Returns port reference, or 0 if unable to create it
+ *
+ * Note: The newly created port is returned in the locked state.
  */
 
 u32 tipc_createport_raw(void *usr_handle,
                        u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
                        void (*wakeup)(struct tipc_port *),
-                       const u32 importance)
+                       const u32 importance,
+                       struct tipc_port **tp_ptr)
 {
        struct port *p_ptr;
        struct tipc_msg *msg;
@@ -237,12 +240,12 @@ u32 tipc_createport_raw(void *usr_handle,
                return 0;
        }
 
-       tipc_port_lock(ref);
        p_ptr->publ.usr_handle = usr_handle;
        p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
        p_ptr->publ.ref = ref;
        msg = &p_ptr->publ.phdr;
-       msg_init(msg, DATA_LOW, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, 0);
+       msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE,
+                0);
        msg_set_orignode(msg, tipc_own_addr);
        msg_set_prevnode(msg, tipc_own_addr);
        msg_set_origport(msg, ref);
@@ -261,7 +264,7 @@ u32 tipc_createport_raw(void *usr_handle,
        INIT_LIST_HEAD(&p_ptr->port_list);
        list_add_tail(&p_ptr->port_list, &ports);
        spin_unlock_bh(&tipc_port_list_lock);
-       tipc_port_unlock(p_ptr);
+       *tp_ptr = &p_ptr->publ;
        return ref;
 }
 
@@ -340,7 +343,7 @@ int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
        if (!p_ptr)
                return -EINVAL;
        *isunreliable = port_unreliable(p_ptr);
-       spin_unlock_bh(p_ptr->publ.lock);
+       tipc_port_unlock(p_ptr);
        return TIPC_OK;
 }
 
@@ -369,7 +372,7 @@ int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
        if (!p_ptr)
                return -EINVAL;
        *isunrejectable = port_unreturnable(p_ptr);
-       spin_unlock_bh(p_ptr->publ.lock);
+       tipc_port_unlock(p_ptr);
        return TIPC_OK;
 }
 
@@ -413,13 +416,6 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
        return buf;
 }
 
-int tipc_set_msg_option(struct tipc_port *tp_ptr, const char *opt, const u32 sz)
-{
-       msg_expand(&tp_ptr->phdr, msg_destnode(&tp_ptr->phdr));
-       msg_set_options(&tp_ptr->phdr, opt, sz);
-       return TIPC_OK;
-}
-
 int tipc_reject_msg(struct sk_buff *buf, u32 err)
 {
        struct tipc_msg *msg = buf_msg(buf);
@@ -632,7 +628,7 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf)
                                             msg_orignode(msg),
                                             msg_destport(msg),
                                             tipc_own_addr,
-                                            DATA_HIGH,
+                                            TIPC_HIGH_IMPORTANCE,
                                             TIPC_CONN_MSG,
                                             err,
                                             0,
@@ -843,7 +839,7 @@ static void port_dispatcher_sigh(void *dummy)
                                u32 peer_port = port_peerport(p_ptr);
                                u32 peer_node = port_peernode(p_ptr);
 
-                               spin_unlock_bh(p_ptr->publ.lock);
+                               tipc_port_unlock(p_ptr);
                                if (unlikely(!connected)) {
                                        if (unlikely(published))
                                                goto reject;
@@ -867,7 +863,7 @@ static void port_dispatcher_sigh(void *dummy)
                case TIPC_DIRECT_MSG:{
                                tipc_msg_event cb = up_ptr->msg_cb;
 
-                               spin_unlock_bh(p_ptr->publ.lock);
+                               tipc_port_unlock(p_ptr);
                                if (unlikely(connected))
                                        goto reject;
                                if (unlikely(!cb))
@@ -882,7 +878,7 @@ static void port_dispatcher_sigh(void *dummy)
                case TIPC_NAMED_MSG:{
                                tipc_named_msg_event cb = up_ptr->named_msg_cb;
 
-                               spin_unlock_bh(p_ptr->publ.lock);
+                               tipc_port_unlock(p_ptr);
                                if (unlikely(connected))
                                        goto reject;
                                if (unlikely(!cb))
@@ -913,7 +909,7 @@ err:
                                u32 peer_port = port_peerport(p_ptr);
                                u32 peer_node = port_peernode(p_ptr);
 
-                               spin_unlock_bh(p_ptr->publ.lock);
+                               tipc_port_unlock(p_ptr);
                                if (!connected || !cb)
                                        break;
                                if (msg_origport(msg) != peer_port)
@@ -929,7 +925,7 @@ err:
                case TIPC_DIRECT_MSG:{
                                tipc_msg_err_event cb = up_ptr->err_cb;
 
-                               spin_unlock_bh(p_ptr->publ.lock);
+                               tipc_port_unlock(p_ptr);
                                if (connected || !cb)
                                        break;
                                skb_pull(buf, msg_hdr_sz(msg));
@@ -942,7 +938,7 @@ err:
                                tipc_named_msg_err_event cb =
                                        up_ptr->named_err_cb;
 
-                               spin_unlock_bh(p_ptr->publ.lock);
+                               tipc_port_unlock(p_ptr);
                                if (connected || !cb)
                                        break;
                                dseq.type =  msg_nametype(msg);
@@ -1059,6 +1055,7 @@ int tipc_createport(u32 user_ref,
 {
        struct user_port *up_ptr;
        struct port *p_ptr;
+       struct tipc_port *tp_ptr;
        u32 ref;
 
        up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
@@ -1066,12 +1063,13 @@ int tipc_createport(u32 user_ref,
                warn("Port creation failed, no memory\n");
                return -ENOMEM;
        }
-       ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance);
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr) {
+       ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup,
+                                 importance, &tp_ptr);
+       if (ref == 0) {
                kfree(up_ptr);
                return -ENOMEM;
        }
+       p_ptr = (struct port *)tp_ptr;
 
        p_ptr->user_port = up_ptr;
        up_ptr->user_ref = user_ref;
@@ -1107,7 +1105,7 @@ int tipc_portimportance(u32 ref, unsigned int *importance)
        if (!p_ptr)
                return -EINVAL;
        *importance = (unsigned int)msg_importance(&p_ptr->publ.phdr);
-       spin_unlock_bh(p_ptr->publ.lock);
+       tipc_port_unlock(p_ptr);
        return TIPC_OK;
 }
 
@@ -1122,7 +1120,7 @@ int tipc_set_portimportance(u32 ref, unsigned int imp)
        if (!p_ptr)
                return -EINVAL;
        msg_set_importance(&p_ptr->publ.phdr, (u32)imp);
-       spin_unlock_bh(p_ptr->publ.lock);
+       tipc_port_unlock(p_ptr);
        return TIPC_OK;
 }
 
@@ -1246,6 +1244,28 @@ exit:
        return res;
 }
 
+/**
+ * tipc_disconnect_port - disconnect port from peer
+ *
+ * Port must be locked.
+ */
+
+int tipc_disconnect_port(struct tipc_port *tp_ptr)
+{
+       int res;
+
+       if (tp_ptr->connected) {
+               tp_ptr->connected = 0;
+               /* let timer expire on it's own to avoid deadlock! */
+               tipc_nodesub_unsubscribe(
+                       &((struct port *)tp_ptr)->subscription);
+               res = TIPC_OK;
+       } else {
+               res = -ENOTCONN;
+       }
+       return res;
+}
+
 /*
  * tipc_disconnect(): Disconnect port form peer.
  *                    This is a node local operation.
@@ -1254,17 +1274,12 @@ exit:
 int tipc_disconnect(u32 ref)
 {
        struct port *p_ptr;
-       int res = -ENOTCONN;
+       int res;
 
        p_ptr = tipc_port_lock(ref);
        if (!p_ptr)
                return -EINVAL;
-       if (p_ptr->publ.connected) {
-               p_ptr->publ.connected = 0;
-               /* let timer expire on it's own to avoid deadlock! */
-               tipc_nodesub_unsubscribe(&p_ptr->subscription);
-               res = TIPC_OK;
-       }
+       res = tipc_disconnect_port((struct tipc_port *)p_ptr);
        tipc_port_unlock(p_ptr);
        return res;
 }