/** * tipc_create - create a TIPC socket * @sock: pre-allocated socket structure * @protocol: protocol indicator (must be 0) * * This routine creates and attaches a 'struct sock' to the 'struct socket', * then create and attaches a TIPC port to the 'struct sock' part. * * Returns 0 on success, errno otherwise */ static int tipc_create(struct socket *sock, int protocol) { struct tipc_sock *tsock; struct tipc_port *port; struct sock *sk; u32 ref; if (unlikely(protocol != 0)) return -EPROTONOSUPPORT; ref = tipc_createport_raw(NULL, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE); if (unlikely(!ref)) return -ENOMEM; sock->state = SS_UNCONNECTED; switch (sock->type) { case SOCK_STREAM: sock->ops = &stream_ops; break; case SOCK_SEQPACKET: sock->ops = &packet_ops; break; case SOCK_DGRAM: tipc_set_portunreliable(ref, 1); /* fall through */ case SOCK_RDM: tipc_set_portunreturnable(ref, 1); sock->ops = &msg_ops; sock->state = SS_READY; break; default: tipc_deleteport(ref); return -EPROTOTYPE; } sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1); if (!sk) { tipc_deleteport(ref); return -ENOMEM; } sock_init_data(sock, sk); init_waitqueue_head(sk->sk_sleep); sk->sk_rcvtimeo = 8 * HZ; /* default connect timeout = 8s */ tsock = tipc_sk(sk); port = tipc_get_port(ref); tsock->p = port; port->usr_handle = tsock; init_MUTEX(&tsock->sem); dbg("sock_create: %x\n",tsock); atomic_inc(&tipc_user_count); return 0; }
static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov, unsigned int ol) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); u32 value; int res; if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM)) return 0; if (lvl != SOL_TIPC) return -ENOPROTOOPT; if (ol < sizeof(value)) return -EINVAL; res = get_user(value, (u32 __user *)ov); if (res) return res; lock_sock(sk); switch (opt) { case TIPC_IMPORTANCE: res = tipc_set_portimportance(tport->ref, value); break; case TIPC_SRC_DROPPABLE: if (sock->type != SOCK_STREAM) res = tipc_set_portunreliable(tport->ref, value); else res = -ENOPROTOOPT; break; case TIPC_DEST_DROPPABLE: res = tipc_set_portunreturnable(tport->ref, value); break; case TIPC_CONN_TIMEOUT: tipc_sk(sk)->conn_timeout = value; /* no need to set "res", since already 0 at this point */ break; default: res = -EINVAL; } release_sock(sk); return res; }
static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov, int ol) { struct tipc_sock *tsock = tipc_sk(sock->sk); u32 value; int res; if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM)) return 0; if (lvl != SOL_TIPC) return -ENOPROTOOPT; if (ol < sizeof(value)) return -EINVAL; if ((res = get_user(value, (u32 __user *)ov))) return res; if (down_interruptible(&tsock->sem)) return -ERESTARTSYS; switch (opt) { case TIPC_IMPORTANCE: res = tipc_set_portimportance(tsock->p->ref, value); break; case TIPC_SRC_DROPPABLE: if (sock->type != SOCK_STREAM) res = tipc_set_portunreliable(tsock->p->ref, value); else res = -ENOPROTOOPT; break; case TIPC_DEST_DROPPABLE: res = tipc_set_portunreturnable(tsock->p->ref, value); break; case TIPC_CONN_TIMEOUT: sock->sk->sk_rcvtimeo = (value * HZ / 1000); break; default: res = -EINVAL; } up(&tsock->sem); return res; }
static int tipc_create(struct net *net, struct socket *sock, int protocol, int kern) { const struct proto_ops *ops; socket_state state; struct sock *sk; struct tipc_port *tp_ptr; /* Validate arguments */ if (unlikely(protocol != 0)) return -EPROTONOSUPPORT; switch (sock->type) { case SOCK_STREAM: ops = &stream_ops; state = SS_UNCONNECTED; break; case SOCK_SEQPACKET: ops = &packet_ops; state = SS_UNCONNECTED; break; case SOCK_DGRAM: case SOCK_RDM: ops = &msg_ops; state = SS_READY; break; default: return -EPROTOTYPE; } /* Allocate socket's protocol area */ sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); if (sk == NULL) return -ENOMEM; /* Allocate TIPC port for socket to use */ tp_ptr = tipc_createport_raw(sk, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE); if (unlikely(!tp_ptr)) { sk_free(sk); return -ENOMEM; } /* Finish initializing socket data structures */ sock->ops = ops; sock->state = state; sock_init_data(sock, sk); sk->sk_backlog_rcv = backlog_rcv; tipc_sk(sk)->p = tp_ptr; tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT; spin_unlock_bh(tp_ptr->lock); if (sock->state == SS_READY) { tipc_set_portunreturnable(tp_ptr->ref, 1); if (sock->type == SOCK_DGRAM) tipc_set_portunreliable(tp_ptr->ref, 1); } return 0; }