u32 tipc_msg_tot_importance(struct tipc_msg *m) { if (likely(msg_isdata(m))) { if (likely(msg_orignode(m) == tipc_own_addr)) return msg_importance(m); return msg_importance(m) + 4; } if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) return msg_importance(msg_get_wrapped(m)); return msg_importance(m); }
/** * 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; }
/** * auto_connect - complete connection setup to a remote port * @sock: socket structure * @msg: peer's response message * * Returns 0 on success, errno otherwise */ static int auto_connect(struct socket *sock, struct tipc_msg *msg) { struct tipc_sock *tsock = tipc_sk(sock->sk); struct tipc_port *p_ptr; tsock->peer_name.ref = msg_origport(msg); tsock->peer_name.node = msg_orignode(msg); p_ptr = tipc_port_deref(tsock->p->ref); if (!p_ptr) return -EINVAL; __tipc_connect(tsock->p->ref, p_ptr, &tsock->peer_name); if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE) return -EINVAL; msg_set_importance(&p_ptr->phdr, (u32)msg_importance(msg)); sock->state = SS_CONNECTED; return 0; }
/** * rcvbuf_limit - get proper overload limit of socket receive queue * @sk: socket * @buf: message * * For all connection oriented messages, irrespective of importance, * the default overload value (i.e. 67MB) is set as limit. * * For all connectionless messages, by default new queue limits are * as belows: * * TIPC_LOW_IMPORTANCE (5MB) * TIPC_MEDIUM_IMPORTANCE (10MB) * TIPC_HIGH_IMPORTANCE (20MB) * TIPC_CRITICAL_IMPORTANCE (40MB) * * Returns overload limit according to corresponding message importance */ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); unsigned int limit; if (msg_connected(msg)) limit = CONN_OVERLOAD_LIMIT; else limit = sk->sk_rcvbuf << (msg_importance(msg) + 5); return limit; }
static int auto_connect(struct socket *sock, struct tipc_msg *msg) { struct tipc_sock *tsock = tipc_sk(sock->sk); if (msg_errcode(msg)) { sock->state = SS_DISCONNECTING; return -ECONNREFUSED; } tsock->peer_name.ref = msg_origport(msg); tsock->peer_name.node = msg_orignode(msg); tipc_connect2port(tsock->p->ref, &tsock->peer_name); tipc_set_portimportance(tsock->p->ref, msg_importance(msg)); sock->state = SS_CONNECTED; return 0; }
static int rx_queue_full(struct tipc_msg *msg, u32 queue_size, u32 base) { u32 threshold; u32 imp = msg_importance(msg); if (imp == TIPC_LOW_IMPORTANCE) threshold = base; else if (imp == TIPC_MEDIUM_IMPORTANCE) threshold = base * 2; else if (imp == TIPC_HIGH_IMPORTANCE) threshold = base * 100; else return 0; if (msg_connected(msg)) threshold *= 4; return queue_size >= threshold; }
static int queue_overloaded(u32 queue_size, u32 base, struct tipc_msg *msg) { u32 threshold; u32 imp = msg_importance(msg); if (imp == TIPC_LOW_IMPORTANCE) threshold = base; else if (imp == TIPC_MEDIUM_IMPORTANCE) threshold = base * 2; else if (imp == TIPC_HIGH_IMPORTANCE) threshold = base * 100; else return 0; if (msg_connected(msg)) threshold *= 4; return (queue_size > threshold); }
static int accept(struct socket *sock, struct socket *new_sock, int flags) { struct sock *sk = sock->sk; struct sk_buff *buf; int res; lock_sock(sk); if (sock->state != SS_LISTENING) { res = -EINVAL; goto exit; } while (skb_queue_empty(&sk->sk_receive_queue)) { if (flags & O_NONBLOCK) { res = -EWOULDBLOCK; goto exit; } release_sock(sk); res = wait_event_interruptible(*sk_sleep(sk), (!skb_queue_empty(&sk->sk_receive_queue))); lock_sock(sk); if (res) goto exit; } buf = skb_peek(&sk->sk_receive_queue); res = tipc_create(sock_net(sock->sk), new_sock, 0, 0); if (!res) { struct sock *new_sk = new_sock->sk; struct tipc_sock *new_tsock = tipc_sk(new_sk); struct tipc_port *new_tport = new_tsock->p; u32 new_ref = new_tport->ref; struct tipc_msg *msg = buf_msg(buf); lock_sock(new_sk); /* * Reject any stray messages received by new socket * before the socket lock was taken (very, very unlikely) */ reject_rx_queue(new_sk); /* Connect new socket to it's peer */ new_tsock->peer_name.ref = msg_origport(msg); new_tsock->peer_name.node = msg_orignode(msg); tipc_connect2port(new_ref, &new_tsock->peer_name); new_sock->state = SS_CONNECTED; tipc_set_portimportance(new_ref, msg_importance(msg)); if (msg_named(msg)) { new_tport->conn_type = msg_nametype(msg); new_tport->conn_instance = msg_nameinst(msg); } /* * Respond to 'SYN-' by discarding it & returning 'ACK'-. * Respond to 'SYN+' by queuing it on new socket. */ if (!msg_data_sz(msg)) { struct msghdr m = {NULL,}; advance_rx_queue(sk); send_packet(NULL, new_sock, &m, 0); } else { __skb_dequeue(&sk->sk_receive_queue); __skb_queue_head(&new_sk->sk_receive_queue, buf); } release_sock(new_sk); } exit: release_sock(sk); return res; }
static int accept(struct socket *sock, struct socket *newsock, int flags) { struct tipc_sock *tsock = tipc_sk(sock->sk); struct sk_buff *buf; int res = -EFAULT; if (sock->state == SS_READY) return -EOPNOTSUPP; if (sock->state != SS_LISTENING) return -EINVAL; if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && (flags & O_NONBLOCK))) return -EWOULDBLOCK; if (down_interruptible(&tsock->sem)) return -ERESTARTSYS; if (wait_event_interruptible(*sock->sk->sk_sleep, skb_queue_len(&sock->sk->sk_receive_queue))) { res = -ERESTARTSYS; goto exit; } buf = skb_peek(&sock->sk->sk_receive_queue); res = tipc_create(newsock, 0); if (!res) { struct tipc_sock *new_tsock = tipc_sk(newsock->sk); struct tipc_portid id; struct tipc_msg *msg = buf_msg(buf); u32 new_ref = new_tsock->p->ref; id.ref = msg_origport(msg); id.node = msg_orignode(msg); tipc_connect2port(new_ref, &id); newsock->state = SS_CONNECTED; tipc_set_portimportance(new_ref, msg_importance(msg)); if (msg_named(msg)) { new_tsock->p->conn_type = msg_nametype(msg); new_tsock->p->conn_instance = msg_nameinst(msg); } /* * Respond to 'SYN-' by discarding it & returning 'ACK'-. * Respond to 'SYN+' by queuing it on new socket. */ msg_dbg(msg,"<ACC<: "); if (!msg_data_sz(msg)) { struct msghdr m = {NULL,}; send_packet(NULL, newsock, &m, 0); advance_queue(tsock); } else { sock_lock(tsock); skb_dequeue(&sock->sk->sk_receive_queue); sock_unlock(tsock); skb_queue_head(&newsock->sk->sk_receive_queue, buf); } } exit: up(&tsock->sem); return res; }