/** * tipc_msg_build - create buffer chain containing specified header and data * @mhdr: Message header, to be prepended to data * @m: User message * @offset: Posision in iov to start copying from * @dsz: Total length of user data * @pktmax: Max packet size that can be used * @list: Buffer or chain of buffers to be returned to caller * * Returns message data size or errno: -ENOMEM, -EFAULT */ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset, int dsz, int pktmax, struct sk_buff_head *list) { int mhsz = msg_hdr_sz(mhdr); int msz = mhsz + dsz; int pktno = 1; int pktsz; int pktrem = pktmax; int drem = dsz; struct tipc_msg pkthdr; struct sk_buff *skb; char *pktpos; int rc; msg_set_size(mhdr, msz); /* No fragmentation needed? */ if (likely(msz <= pktmax)) { skb = tipc_buf_acquire(msz); if (unlikely(!skb)) return -ENOMEM; __skb_queue_tail(list, skb); skb_copy_to_linear_data(skb, mhdr, mhsz); pktpos = skb->data + mhsz; if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, dsz)) return dsz; rc = -EFAULT; goto error; } /* Prepare reusable fragment header */ tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(mhdr)); msg_set_size(&pkthdr, pktmax); msg_set_fragm_no(&pkthdr, pktno); /* Prepare first fragment */ skb = tipc_buf_acquire(pktmax); if (!skb) return -ENOMEM; __skb_queue_tail(list, skb); pktpos = skb->data; skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE); pktpos += INT_H_SIZE; pktrem -= INT_H_SIZE; skb_copy_to_linear_data_offset(skb, INT_H_SIZE, mhdr, mhsz); pktpos += mhsz; pktrem -= mhsz; do { if (drem < pktrem) pktrem = drem; if (memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, pktrem)) { rc = -EFAULT; goto error; } drem -= pktrem; offset += pktrem; if (!drem) break; /* Prepare new fragment: */ if (drem < (pktmax - INT_H_SIZE)) pktsz = drem + INT_H_SIZE; else pktsz = pktmax; skb = tipc_buf_acquire(pktsz); if (!skb) { rc = -ENOMEM; goto error; } __skb_queue_tail(list, skb); msg_set_type(&pkthdr, FRAGMENT); msg_set_size(&pkthdr, pktsz); msg_set_fragm_no(&pkthdr, ++pktno); skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE); pktpos = skb->data + INT_H_SIZE; pktrem = pktsz - INT_H_SIZE; } while (1); msg_set_type(buf_msg(skb), LAST_FRAGMENT); return dsz; error: __skb_queue_purge(list); __skb_queue_head_init(list); return rc; }
/** * tipc_msg_reverse(): swap source and destination addresses and add error code * @buf: buffer containing message to be reversed * @dnode: return value: node where to send message after reversal * @err: error code to be set in message * Consumes buffer if failure * Returns true if success, otherwise false */ bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err) { struct tipc_msg *msg = buf_msg(buf); uint imp = msg_importance(msg); struct tipc_msg ohdr; uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE); if (skb_linearize(buf)) goto exit; if (msg_dest_droppable(msg)) goto exit; if (msg_errcode(msg)) goto exit; memcpy(&ohdr, msg, msg_hdr_sz(msg)); imp = min_t(uint, imp + 1, TIPC_CRITICAL_IMPORTANCE); if (msg_isdata(msg)) msg_set_importance(msg, imp); msg_set_errcode(msg, err); msg_set_origport(msg, msg_destport(&ohdr)); msg_set_destport(msg, msg_origport(&ohdr)); msg_set_prevnode(msg, tipc_own_addr); if (!msg_short(msg)) { msg_set_orignode(msg, msg_destnode(&ohdr)); msg_set_destnode(msg, msg_orignode(&ohdr)); } msg_set_size(msg, msg_hdr_sz(msg) + rdsz); skb_trim(buf, msg_size(msg)); skb_orphan(buf); *dnode = msg_orignode(&ohdr); return true; exit: kfree_skb(buf); return false; }
/* tipc_msg_reassemble() - clone a buffer chain of fragments and * reassemble the clones into one message */ struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list) { struct sk_buff *skb; struct sk_buff *frag = NULL; struct sk_buff *head = NULL; int hdr_sz; /* Copy header if single buffer */ if (skb_queue_len(list) == 1) { skb = skb_peek(list); hdr_sz = skb_headroom(skb) + msg_hdr_sz(buf_msg(skb)); return __pskb_copy(skb, hdr_sz, GFP_ATOMIC); } /* Clone all fragments and reassemble */ skb_queue_walk(list, skb) { frag = skb_clone(skb, GFP_ATOMIC); if (!frag) goto error; frag->next = NULL; if (tipc_buf_append(&head, &frag)) break; if (!head) goto error; }
/** * tipc_msg_build - create message using specified header and data * * Note: Caller must not hold any locks in case copy_from_user() is interrupted! * * Returns message data size or errno */ int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, unsigned int len, int max_size, struct sk_buff **buf) { int dsz, sz, hsz; unsigned char *to; dsz = len; hsz = msg_hdr_sz(hdr); sz = hsz + dsz; msg_set_size(hdr, sz); if (unlikely(sz > max_size)) { *buf = NULL; return dsz; } *buf = tipc_buf_acquire(sz); if (!(*buf)) return -ENOMEM; skb_copy_to_linear_data(*buf, hdr, hsz); to = (*buf)->data + hsz; if (len && memcpy_fromiovecend(to, msg_sect, 0, dsz)) { kfree_skb(*buf); *buf = NULL; return -EFAULT; } return dsz; }
int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, u32 num_sect, unsigned int total_len, int max_size, int usrmem, struct sk_buff **buf) { int dsz, sz, hsz, pos, res, cnt; dsz = total_len; pos = hsz = msg_hdr_sz(hdr); sz = hsz + dsz; msg_set_size(hdr, sz); if (unlikely(sz > max_size)) { *buf = NULL; return dsz; } *buf = tipc_buf_acquire(sz); if (!(*buf)) return -ENOMEM; skb_copy_to_linear_data(*buf, hdr, hsz); for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) { if (likely(usrmem)) res = !copy_from_user((*buf)->data + pos, msg_sect[cnt].iov_base, msg_sect[cnt].iov_len); else skb_copy_to_linear_data_offset(*buf, pos, msg_sect[cnt].iov_base, msg_sect[cnt].iov_len); pos += msg_sect[cnt].iov_len; } if (likely(res)) return dsz; buf_discard(*buf); *buf = NULL; return -EFAULT; }
void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) { u32 usr = msg_user(msg); tipc_printf(buf, KERN_DEBUG); tipc_printf(buf, str); switch (usr) { case MSG_BUNDLER: tipc_printf(buf, "BNDL::"); tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg)); break; case BCAST_PROTOCOL: tipc_printf(buf, "BCASTP::"); break; case MSG_FRAGMENTER: tipc_printf(buf, "FRAGM::"); switch (msg_type(msg)) { case FIRST_FRAGMENT: tipc_printf(buf, "FIRST:"); break; case FRAGMENT: tipc_printf(buf, "BODY:"); break; case LAST_FRAGMENT: tipc_printf(buf, "LAST:"); break; default: tipc_printf(buf, "UNKNOWN:%x", msg_type(msg)); } tipc_printf(buf, "NO(%u/%u):", msg_long_msgno(msg), msg_fragm_no(msg)); break; case TIPC_LOW_IMPORTANCE: case TIPC_MEDIUM_IMPORTANCE: case TIPC_HIGH_IMPORTANCE: case TIPC_CRITICAL_IMPORTANCE: tipc_printf(buf, "DAT%u:", msg_user(msg)); if (msg_short(msg)) { tipc_printf(buf, "CON:"); break; } switch (msg_type(msg)) { case TIPC_CONN_MSG: tipc_printf(buf, "CON:"); break; case TIPC_MCAST_MSG: tipc_printf(buf, "MCST:"); break; case TIPC_NAMED_MSG: tipc_printf(buf, "NAM:"); break; case TIPC_DIRECT_MSG: tipc_printf(buf, "DIR:"); break; default: tipc_printf(buf, "UNKNOWN TYPE %u", msg_type(msg)); } if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case NAME_DISTRIBUTOR: tipc_printf(buf, "NMD::"); switch (msg_type(msg)) { case PUBLICATION: tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20); /* Items */ break; case WITHDRAWAL: tipc_printf(buf, "WDRW:"); break; default: tipc_printf(buf, "UNKNOWN:%x", msg_type(msg)); } if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case CONN_MANAGER: tipc_printf(buf, "CONN_MNG:"); switch (msg_type(msg)) { case CONN_PROBE: tipc_printf(buf, "PROBE:"); break; case CONN_PROBE_REPLY: tipc_printf(buf, "PROBE_REPLY:"); break; case CONN_ACK: tipc_printf(buf, "CONN_ACK:"); tipc_printf(buf, "ACK(%u):", msg_msgcnt(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); } if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case LINK_PROTOCOL: switch (msg_type(msg)) { case STATE_MSG: tipc_printf(buf, "STATE:"); tipc_printf(buf, "%s:", msg_probe(msg) ? "PRB" : ""); tipc_printf(buf, "NXS(%u):", msg_next_sent(msg)); tipc_printf(buf, "GAP(%u):", msg_seq_gap(msg)); tipc_printf(buf, "LSTBC(%u):", msg_last_bcast(msg)); break; case RESET_MSG: tipc_printf(buf, "RESET:"); if (msg_size(msg) != msg_hdr_sz(msg)) tipc_printf(buf, "BEAR:%s:", msg_data(msg)); break; case ACTIVATE_MSG: tipc_printf(buf, "ACTIVATE:"); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); } tipc_printf(buf, "PLANE(%c):", msg_net_plane(msg)); tipc_printf(buf, "SESS(%u):", msg_session(msg)); break; case CHANGEOVER_PROTOCOL: tipc_printf(buf, "TUNL:"); switch (msg_type(msg)) { case DUPLICATE_MSG: tipc_printf(buf, "DUPL:"); break; case ORIGINAL_MSG: tipc_printf(buf, "ORIG:"); tipc_printf(buf, "EXP(%u)", msg_msgcnt(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); } break; case LINK_CONFIG: tipc_printf(buf, "CFG:"); switch (msg_type(msg)) { case DSC_REQ_MSG: tipc_printf(buf, "DSC_REQ:"); break; case DSC_RESP_MSG: tipc_printf(buf, "DSC_RESP:"); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x:", msg_type(msg)); break; } break; default: tipc_printf(buf, "UNKNOWN USER:"******"NO_NAME:"); break; case TIPC_ERR_NO_PORT: tipc_printf(buf, "NO_PORT:"); break; case TIPC_ERR_NO_NODE: tipc_printf(buf, "NO_PROC:"); break; case TIPC_ERR_OVERLOAD: tipc_printf(buf, "OVERLOAD:"); break; case TIPC_CONN_SHUTDOWN: tipc_printf(buf, "SHUTDOWN:"); break; default: tipc_printf(buf, "UNKNOWN ERROR(%x):", msg_errcode(msg)); } default: break; } tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg
static int recv_msg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; struct tipc_msg *msg; long timeout; unsigned int sz; u32 err; int res; /* Catch invalid receive requests */ if (unlikely(!buf_len)) return -EINVAL; lock_sock(sk); if (unlikely(sock->state == SS_UNCONNECTED)) { res = -ENOTCONN; goto exit; } /* will be updated in set_orig_addr() if needed */ m->msg_namelen = 0; timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); restart: /* Look for a message in receive queue; wait if necessary */ while (skb_queue_empty(&sk->sk_receive_queue)) { if (sock->state == SS_DISCONNECTING) { res = -ENOTCONN; goto exit; } if (timeout <= 0L) { res = timeout ? timeout : -EWOULDBLOCK; goto exit; } release_sock(sk); timeout = wait_event_interruptible_timeout(*sk_sleep(sk), tipc_rx_ready(sock), timeout); lock_sock(sk); } /* Look at first message in receive queue */ buf = skb_peek(&sk->sk_receive_queue); msg = buf_msg(buf); sz = msg_data_sz(msg); err = msg_errcode(msg); /* Complete connection setup for an implied connect */ if (unlikely(sock->state == SS_CONNECTING)) { res = auto_connect(sock, msg); if (res) goto exit; } /* Discard an empty non-errored message & try again */ if ((!sz) && (!err)) { advance_rx_queue(sk); goto restart; } /* Capture sender's address (optional) */ set_orig_addr(m, msg); /* Capture ancillary data (optional) */ res = anc_data_recv(m, msg, tport); if (res) goto exit; /* Capture message data (if valid) & compute return value (always) */ if (!err) { if (unlikely(buf_len < sz)) { sz = buf_len; m->msg_flags |= MSG_TRUNC; } res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg), m->msg_iov, sz); if (res) goto exit; res = sz; } else { if ((sock->state == SS_READY) || ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)) res = 0; else res = -ECONNRESET; } /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { if ((sock->state != SS_READY) && (++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) tipc_acknowledge(tport->ref, tport->conn_unacked); advance_rx_queue(sk); } exit: release_sock(sk); return res; }
static int send_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); 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; lock_sock(sk); /* Handle special cases where there is no connection */ if (unlikely(sock->state != SS_CONNECTED)) { if (sock->state == SS_UNCONNECTED) { res = send_packet(NULL, sock, m, total_len); goto exit; } else if (sock->state == SS_DISCONNECTING) { res = -EPIPE; goto exit; } else { res = -ENOTCONN; goto exit; } } if (unlikely(m->msg_name)) { res = -EISCONN; goto exit; } if ((total_len > (unsigned)INT_MAX) || (m->msg_iovlen > (unsigned)INT_MAX)) { res = -EMSGSIZE; goto exit; } /* * Send each iovec entry using one or more messages * * Note: This algorithm is good for the most likely case * (i.e. one large iovec entry), but could be improved to pass sets * of small iovec entries into send_packet(). */ curr_iov = m->msg_iov; curr_iovlen = m->msg_iovlen; my_msg.msg_iov = &my_iov; my_msg.msg_iovlen = 1; my_msg.msg_flags = m->msg_flags; my_msg.msg_name = NULL; bytes_sent = 0; 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 = 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; res = send_packet(NULL, sock, &my_msg, bytes_to_send); if (res < 0) { if (bytes_sent) res = bytes_sent; goto exit; } curr_left -= bytes_to_send; curr_start += bytes_to_send; bytes_sent += bytes_to_send; } curr_iov++; } res = bytes_sent; exit: release_sock(sk); return res; }
static int recv_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; struct tipc_msg *msg; long timeout; unsigned int sz; int sz_to_copy, target, needed; int sz_copied = 0; u32 err; int res = 0; /* Catch invalid receive attempts */ if (unlikely(!buf_len)) return -EINVAL; lock_sock(sk); if (unlikely((sock->state == SS_UNCONNECTED) || (sock->state == SS_CONNECTING))) { res = -ENOTCONN; goto exit; } /* will be updated in set_orig_addr() if needed */ m->msg_namelen = 0; target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); restart: /* Look for a message in receive queue; wait if necessary */ while (skb_queue_empty(&sk->sk_receive_queue)) { if (sock->state == SS_DISCONNECTING) { res = -ENOTCONN; goto exit; } if (timeout <= 0L) { res = timeout ? timeout : -EWOULDBLOCK; goto exit; } release_sock(sk); timeout = wait_event_interruptible_timeout(*sk_sleep(sk), tipc_rx_ready(sock), timeout); lock_sock(sk); } /* Look at first message in receive queue */ buf = skb_peek(&sk->sk_receive_queue); msg = buf_msg(buf); sz = msg_data_sz(msg); err = msg_errcode(msg); /* Discard an empty non-errored message & try again */ if ((!sz) && (!err)) { advance_rx_queue(sk); goto restart; } /* Optionally capture sender's address & ancillary data of first msg */ if (sz_copied == 0) { set_orig_addr(m, msg); res = anc_data_recv(m, msg, tport); if (res) goto exit; } /* Capture message data (if valid) & compute return value (always) */ if (!err) { u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle); sz -= offset; needed = (buf_len - sz_copied); sz_to_copy = (sz <= needed) ? sz : needed; res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg) + offset, m->msg_iov, sz_to_copy); if (res) goto exit; sz_copied += sz_to_copy; if (sz_to_copy < sz) { if (!(flags & MSG_PEEK)) TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)(offset + sz_to_copy); goto exit; } } else { if (sz_copied != 0) goto exit; /* can't add error msg to valid data */ if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) res = 0; else res = -ECONNRESET; } /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { if (unlikely(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) tipc_acknowledge(tport->ref, tport->conn_unacked); advance_rx_queue(sk); } /* Loop around if more data is required */ if ((sz_copied < buf_len) && /* didn't get all requested data */ (!skb_queue_empty(&sk->sk_receive_queue) || (sz_copied < target)) && /* and more is ready or required */ (!(flags & MSG_PEEK)) && /* and aren't just peeking at data */ (!err)) /* and haven't reached a FIN */ goto restart; exit: release_sock(sk); return sz_copied ? sz_copied : res; }
void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str) { u32 usr = msg_user(msg); tipc_printf(buf, str); switch (usr) { case MSG_BUNDLER: tipc_printf(buf, "BNDL::"); tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg)); break; case BCAST_PROTOCOL: tipc_printf(buf, "BCASTP::"); break; case MSG_FRAGMENTER: tipc_printf(buf, "FRAGM::"); switch (msg_type(msg)) { case FIRST_FRAGMENT: tipc_printf(buf, "FIRST:"); break; case FRAGMENT: tipc_printf(buf, "BODY:"); break; case LAST_FRAGMENT: tipc_printf(buf, "LAST:"); break; default: tipc_printf(buf, "UNKNOWN:%x",msg_type(msg)); } tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg), msg_fragm_no(msg)); break; case TIPC_LOW_IMPORTANCE: case TIPC_MEDIUM_IMPORTANCE: case TIPC_HIGH_IMPORTANCE: case TIPC_CRITICAL_IMPORTANCE: tipc_printf(buf, "DAT%u:", msg_user(msg)); if (msg_short(msg)) { tipc_printf(buf, "CON:"); break; } switch (msg_type(msg)) { case TIPC_CONN_MSG: tipc_printf(buf, "CON:"); break; case TIPC_MCAST_MSG: tipc_printf(buf, "MCST:"); break; case TIPC_NAMED_MSG: tipc_printf(buf, "NAM:"); break; case TIPC_DIRECT_MSG: tipc_printf(buf, "DIR:"); break; default: tipc_printf(buf, "UNKNOWN TYPE %u",msg_type(msg)); } if (msg_routed(msg) && !msg_non_seq(msg)) tipc_printf(buf, "ROUT:"); if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case NAME_DISTRIBUTOR: tipc_printf(buf, "NMD::"); switch (msg_type(msg)) { case PUBLICATION: tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20); /* Items */ break; case WITHDRAWAL: tipc_printf(buf, "WDRW:"); break; default: tipc_printf(buf, "UNKNOWN:%x",msg_type(msg)); } if (msg_routed(msg)) tipc_printf(buf, "ROUT:"); if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case CONN_MANAGER: tipc_printf(buf, "CONN_MNG:"); switch (msg_type(msg)) { case CONN_PROBE: tipc_printf(buf, "PROBE:"); break; case CONN_PROBE_REPLY: tipc_printf(buf, "PROBE_REPLY:"); break; case CONN_ACK: tipc_printf(buf, "CONN_ACK:"); tipc_printf(buf, "ACK(%u):",msg_msgcnt(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); } if (msg_routed(msg)) tipc_printf(buf, "ROUT:"); if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):",msg_reroute_cnt(msg)); break; case LINK_PROTOCOL: tipc_printf(buf, "PROT:TIM(%u):",msg_timestamp(msg)); switch (msg_type(msg)) { case STATE_MSG: tipc_printf(buf, "STATE:"); tipc_printf(buf, "%s:",msg_probe(msg) ? "PRB" :""); tipc_printf(buf, "NXS(%u):",msg_next_sent(msg)); tipc_printf(buf, "GAP(%u):",msg_seq_gap(msg)); tipc_printf(buf, "LSTBC(%u):",msg_last_bcast(msg)); break; case RESET_MSG: tipc_printf(buf, "RESET:"); if (msg_size(msg) != msg_hdr_sz(msg)) tipc_printf(buf, "BEAR:%s:",msg_data(msg)); break; case ACTIVATE_MSG: tipc_printf(buf, "ACTIVATE:"); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); } tipc_printf(buf, "PLANE(%c):",msg_net_plane(msg)); tipc_printf(buf, "SESS(%u):",msg_session(msg)); break; case CHANGEOVER_PROTOCOL: tipc_printf(buf, "TUNL:"); switch (msg_type(msg)) { case DUPLICATE_MSG: tipc_printf(buf, "DUPL:"); break; case ORIGINAL_MSG: tipc_printf(buf, "ORIG:"); tipc_printf(buf, "EXP(%u)",msg_msgcnt(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); } break; case ROUTE_DISTRIBUTOR: tipc_printf(buf, "ROUTING_MNG:"); switch (msg_type(msg)) { case EXT_ROUTING_TABLE: tipc_printf(buf, "EXT_TBL:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; case LOCAL_ROUTING_TABLE: tipc_printf(buf, "LOCAL_TBL:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; case SLAVE_ROUTING_TABLE: tipc_printf(buf, "DP_TBL:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; case ROUTE_ADDITION: tipc_printf(buf, "ADD:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; case ROUTE_REMOVAL: tipc_printf(buf, "REMOVE:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); } break; case LINK_CONFIG: tipc_printf(buf, "CFG:"); switch (msg_type(msg)) { case DSC_REQ_MSG: tipc_printf(buf, "DSC_REQ:"); break; case DSC_RESP_MSG: tipc_printf(buf, "DSC_RESP:"); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x:",msg_type(msg)); break; } break; default: tipc_printf(buf, "UNKNOWN USER:"******"NO_NAME:"); break; case TIPC_ERR_NO_PORT: tipc_printf(buf, "NO_PORT:"); break; case TIPC_ERR_NO_NODE: tipc_printf(buf, "NO_PROC:"); break; case TIPC_ERR_OVERLOAD: tipc_printf(buf, "OVERLOAD:"); break; case TIPC_CONN_SHUTDOWN: tipc_printf(buf, "SHUTDOWN:"); break; default: tipc_printf(buf, "UNKNOWN ERROR(%x):", msg_errcode(msg)); } default:{} } tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg)); tipc_printf(buf, "SZ(%u):", msg_size(msg)); tipc_printf(buf, "SQNO(%u):", msg_seqno(msg)); if (msg_non_seq(msg)) tipc_printf(buf, "NOSEQ:"); else { tipc_printf(buf, "ACK(%u):", msg_ack(msg)); } tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg)); tipc_printf(buf, "PRND(%x)", msg_prevnode(msg)); if (msg_isdata(msg)) { if (msg_named(msg)) { tipc_printf(buf, "NTYP(%u):", msg_nametype(msg)); tipc_printf(buf, "NINST(%u)", msg_nameinst(msg)); } } if ((usr != LINK_PROTOCOL) && (usr != LINK_CONFIG) && (usr != MSG_BUNDLER)) { if (!msg_short(msg)) { tipc_printf(buf, ":ORIG(%x:%u):", msg_orignode(msg), msg_origport(msg)); tipc_printf(buf, ":DEST(%x:%u):", msg_destnode(msg), msg_destport(msg)); } else { tipc_printf(buf, ":OPRT(%u):", msg_origport(msg)); tipc_printf(buf, ":DPRT(%u):", msg_destport(msg)); } if (msg_routed(msg) && !msg_non_seq(msg)) tipc_printf(buf, ":TSEQN(%u)", msg_transp_seqno(msg)); } if (msg_user(msg) == NAME_DISTRIBUTOR) { tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg)); tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg)); if (msg_routed(msg)) { tipc_printf(buf, ":CSEQN(%u)", msg_transp_seqno(msg)); } } if (msg_user(msg) == LINK_CONFIG) { u32* raw = (u32*)msg; struct tipc_media_addr* orig = (struct tipc_media_addr*)&raw[5]; tipc_printf(buf, ":REQL(%u):", msg_req_links(msg)); tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg)); tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg)); tipc_media_addr_printf(buf, orig); } if (msg_user(msg) == BCAST_PROTOCOL) { tipc_printf(buf, "BCNACK:AFTER(%u):", msg_bcgap_after(msg)); tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg)); } tipc_printf(buf, "\n"); if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) { tipc_msg_print(buf,msg_get_wrapped(msg)," /"); } if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) { tipc_msg_print(buf,msg_get_wrapped(msg)," /"); } }
/* tipc_buf_append(): Append a buffer to the fragment list of another buffer * @*headbuf: in: NULL for first frag, otherwise value returned from prev call * out: set when successful non-complete reassembly, otherwise NULL * @*buf: in: the buffer to append. Always defined * out: head buf after successful complete reassembly, otherwise NULL * Returns 1 when reassembly complete, otherwise 0 */ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) { struct sk_buff *head = *headbuf; struct sk_buff *frag = *buf; struct sk_buff *tail; struct tipc_msg *msg; u32 fragid; int delta; bool headstolen; if (!frag) goto err; msg = buf_msg(frag); fragid = msg_type(msg); frag->next = NULL; skb_pull(frag, msg_hdr_sz(msg)); if (fragid == FIRST_FRAGMENT) { if (unlikely(head)) goto err; if (unlikely(skb_unclone(frag, GFP_ATOMIC))) goto err; head = *headbuf = frag; skb_frag_list_init(head); TIPC_SKB_CB(head)->tail = NULL; *buf = NULL; return 0; } if (!head) goto err; if (skb_try_coalesce(head, frag, &headstolen, &delta)) { kfree_skb_partial(frag, headstolen); } else { tail = TIPC_SKB_CB(head)->tail; if (!skb_has_frag_list(head)) skb_shinfo(head)->frag_list = frag; else tail->next = frag; head->truesize += frag->truesize; head->data_len += frag->len; head->len += frag->len; TIPC_SKB_CB(head)->tail = frag; } if (fragid == LAST_FRAGMENT) { *buf = head; TIPC_SKB_CB(head)->tail = NULL; *headbuf = NULL; return 1; } *buf = NULL; return 0; err: pr_warn_ratelimited("Unable to build fragment list\n"); kfree_skb(*buf); kfree_skb(*headbuf); *buf = *headbuf = NULL; return 0; }
void tipc_cltr_recv_routing_table(struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); struct cluster *c_ptr; struct tipc_node *n_ptr; unchar *node_table; u32 table_size; u32 router; u32 rem_node = msg_remote_node(msg); u32 z_num; u32 c_num; u32 n_num; c_ptr = tipc_cltr_find(rem_node); if (!c_ptr) { c_ptr = tipc_cltr_create(rem_node); if (!c_ptr) { buf_discard(buf); return; } } node_table = buf->data + msg_hdr_sz(msg); table_size = msg_size(msg) - msg_hdr_sz(msg); router = msg_prevnode(msg); z_num = tipc_zone(rem_node); c_num = tipc_cluster(rem_node); switch (msg_type(msg)) { case LOCAL_ROUTING_TABLE: assert(is_slave(tipc_own_addr)); case EXT_ROUTING_TABLE: for (n_num = 1; n_num < table_size; n_num++) { if (node_table[n_num]) { u32 addr = tipc_addr(z_num, c_num, n_num); n_ptr = c_ptr->nodes[n_num]; if (!n_ptr) { n_ptr = tipc_node_create(addr); } if (n_ptr) tipc_node_add_router(n_ptr, router); } } break; case SLAVE_ROUTING_TABLE: assert(!is_slave(tipc_own_addr)); assert(in_own_cluster(c_ptr->addr)); for (n_num = 1; n_num < table_size; n_num++) { if (node_table[n_num]) { u32 slave_num = n_num + LOWEST_SLAVE; u32 addr = tipc_addr(z_num, c_num, slave_num); n_ptr = c_ptr->nodes[slave_num]; if (!n_ptr) { n_ptr = tipc_node_create(addr); } if (n_ptr) tipc_node_add_router(n_ptr, router); } } break; case ROUTE_ADDITION: if (!is_slave(tipc_own_addr)) { assert(!in_own_cluster(c_ptr->addr) || is_slave(rem_node)); } else { assert(in_own_cluster(c_ptr->addr) && !is_slave(rem_node)); } n_ptr = c_ptr->nodes[tipc_node(rem_node)]; if (!n_ptr) n_ptr = tipc_node_create(rem_node); if (n_ptr) tipc_node_add_router(n_ptr, router); break; case ROUTE_REMOVAL: if (!is_slave(tipc_own_addr)) { assert(!in_own_cluster(c_ptr->addr) || is_slave(rem_node)); } else { assert(in_own_cluster(c_ptr->addr) && !is_slave(rem_node)); } n_ptr = c_ptr->nodes[tipc_node(rem_node)]; if (n_ptr) tipc_node_remove_router(n_ptr, router); break; default: assert(!"Illegal routing manager message received\n"); } buf_discard(buf); }