/*
  * include/net/tipc/tipc_port.h: Include file for privileged access to TIPC ports
  * 
- * Copyright (c) 1994-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 1994-2007, Ericsson AB
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * @conn_unacked: number of unacknowledged messages received from peer port
  * @published: non-zero if port has one or more associated names
  * @congested: non-zero if cannot send because of link or port congestion
+ * @max_pkt: maximum packet size "hint" used when building messages sent by port
  * @ref: unique reference to port in TIPC object registry
  * @phdr: preformatted message header used when sending messages
  */
        u32 conn_unacked;
        int published;
        u32 congested;
+       u32 max_pkt;
        u32 ref;
        struct tipc_msg phdr;
 };
 
 /*
  * net/tipc/link.c: TIPC link code
  *
- * Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2004-2006, Wind River Systems
+ * Copyright (c) 1996-2007, Ericsson AB
+ * Copyright (c) 2004-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
         * (Must not hold any locks while building message.)
         */
 
-       res = msg_build(hdr, msg_sect, num_sect, sender->max_pkt,
+       res = msg_build(hdr, msg_sect, num_sect, sender->publ.max_pkt,
                        !sender->user_port, &buf);
 
        read_lock_bh(&tipc_net_lock);
                if (likely(l_ptr)) {
                        if (likely(buf)) {
                                res = link_send_buf_fast(l_ptr, buf,
-                                                        &sender->max_pkt);
+                                                        &sender->publ.max_pkt);
                                if (unlikely(res < 0))
                                        buf_discard(buf);
 exit:
                         * then re-try fast path or fragment the message
                         */
 
-                       sender->max_pkt = link_max_pkt(l_ptr);
+                       sender->publ.max_pkt = link_max_pkt(l_ptr);
                        tipc_node_unlock(node);
                        read_unlock_bh(&tipc_net_lock);
 
 
-                       if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt)
+                       if ((msg_hdr_sz(hdr) + res) <= sender->publ.max_pkt)
                                goto again;
 
                        return link_send_sections_long(sender, msg_sect,
 
 again:
        fragm_no = 1;
-       max_pkt = sender->max_pkt - INT_H_SIZE;
+       max_pkt = sender->publ.max_pkt - INT_H_SIZE;
                /* leave room for tunnel header in case of link changeover */
        fragm_sz = max_pkt - INT_H_SIZE;
                /* leave room for fragmentation header in each fragment */
                        goto reject;
                }
                if (link_max_pkt(l_ptr) < max_pkt) {
-                       sender->max_pkt = link_max_pkt(l_ptr);
+                       sender->publ.max_pkt = link_max_pkt(l_ptr);
                        tipc_node_unlock(node);
                        for (; buf_chain; buf_chain = buf) {
                                buf = buf_chain->next;
 
 /*
  * net/tipc/port.c: TIPC port code
  *
- * Copyright (c) 1992-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 1992-2007, Ericsson AB
+ * Copyright (c) 2004-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
        }
 
        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_set_importance(msg,importance);
        p_ptr->last_in_seqno = 41;
        p_ptr->sent = 1;
-       p_ptr->publ.usr_handle = usr_handle;
        INIT_LIST_HEAD(&p_ptr->wait_list);
        INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
        p_ptr->congested_link = NULL;
-       p_ptr->max_pkt = MAX_PKT_DEFAULT;
        p_ptr->dispatcher = dispatcher;
        p_ptr->wakeup = wakeup;
        p_ptr->user_port = NULL;
        res = TIPC_OK;
 exit:
        tipc_port_unlock(p_ptr);
-       p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref);
+       p_ptr->publ.max_pkt = tipc_link_get_max_pkt(peer->node, ref);
        return res;
 }
 
 
 /*
  * net/tipc/port.h: Include file for TIPC port code
  *
- * Copyright (c) 1994-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 1994-2007, Ericsson AB
+ * Copyright (c) 2004-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * @acked:
  * @publications: list of publications for port
  * @pub_count: total # of publications port has made during its lifetime
- * @max_pkt: maximum packet size "hint" used when building messages sent by port
  * @probing_state:
  * @probing_interval:
  * @last_in_seqno:
        u32 acked;
        struct list_head publications;
        u32 pub_count;
-       u32 max_pkt;
        u32 probing_state;
        u32 probing_interval;
        u32 last_in_seqno;
 
 static int send_stream(struct kiocb *iocb, struct socket *sock,
                       struct msghdr *m, size_t total_len)
 {
+       struct tipc_port *tport;
        struct msghdr my_msg;
        struct iovec my_iov;
        struct iovec *curr_iov;
        int curr_iovlen;
        char __user *curr_start;
+       u32 hdr_size;
        int curr_left;
        int bytes_to_send;
        int bytes_sent;
        int res;
 
-       if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE))
-               return send_packet(iocb, sock, m, total_len);
-
-       /* Can only send large data streams if already connected */
+       /* Handle special cases where there is no connection */
 
        if (unlikely(sock->state != SS_CONNECTED)) {
-               if (sock->state == SS_DISCONNECTING)
+               if (sock->state == SS_UNCONNECTED)
+                       return send_packet(iocb, sock, m, total_len);
+               else if (sock->state == SS_DISCONNECTING)
                        return -EPIPE;
                else
                        return -ENOTCONN;
        my_msg.msg_name = NULL;
        bytes_sent = 0;
 
+       tport = tipc_sk(sock->sk)->p;
+       hdr_size = msg_hdr_sz(&tport->phdr);
+
        while (curr_iovlen--) {
                curr_start = curr_iov->iov_base;
                curr_left = curr_iov->iov_len;
 
                while (curr_left) {
-                       bytes_to_send = (curr_left < TIPC_MAX_USER_MSG_SIZE)
-                               ? curr_left : TIPC_MAX_USER_MSG_SIZE;
+                       bytes_to_send = tport->max_pkt - hdr_size;
+                       if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE)
+                               bytes_to_send = TIPC_MAX_USER_MSG_SIZE;
+                       if (curr_left < bytes_to_send)
+                               bytes_to_send = curr_left;
                        my_iov.iov_base = curr_start;
                        my_iov.iov_len = bytes_to_send;
                        if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) {
-                               return bytes_sent ? bytes_sent : res;
+                               if (bytes_sent != 0)
+                                       res = bytes_sent;
+                               return res;
                        }
                        curr_left -= bytes_to_send;
                        curr_start += bytes_to_send;