// SPDX-License-Identifier: GPL-2.0-or-later /* * NET An implementation of the SOCKET network access protocol. * * Version: @(#)socket.c 1.1.93 18/02/95 * * Authors: Orest Zborowski, <obz@Kodak.COM> * Ross Biro * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * * Fixes: * Anonymous : NOTSOCK/BADF cleanup. Error fix in * shutdown() * Alan Cox : verify_area() fixes * Alan Cox : Removed DDI * Jonathan Kamens : SOCK_DGRAM reconnect bug * Alan Cox : Moved a load of checks to the very * top level. * Alan Cox : Move address structures to/from user * mode above the protocol layers. * Rob Janssen : Allow 0 length sends. * Alan Cox : Asynchronous I/O support (cribbed from the * tty drivers). * Niibe Yutaka : Asynchronous I/O for writes (4.4BSD style) * Jeff Uphoff : Made max number of sockets command-line * configurable. * Matti Aarnio : Made the number of sockets dynamic, * to be allocated when needed, and mr. * Uphoff's max is used as max to be * allowed to allocate. * Linus : Argh. removed all the socket allocation * altogether: it's in the inode now. * Alan Cox : Made sock_alloc()/sock_release() public * for NetROM and future kernel nfsd type * stuff. * Alan Cox : sendmsg/recvmsg basics. * Tom Dyas : Export net symbols. * Marcin Dalecki : Fixed problems with CONFIG_NET="n". * Alan Cox : Added thread locking to sys_* calls * for sockets. May have errors at the * moment. * Kevin Buhr : Fixed the dumb errors in the above. * Andi Kleen : Some small cleanups, optimizations, * and fixed a copy_from_user() bug. * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0) * Tigran Aivazian : Made listen(2) backlog sanity checks * protocol-independent * * This module is effectively the top level interface to the BSD socket * paradigm. * * Based upon Swansea University Computer Society NET3.039
*/
if (ops->show_fdinfo)
ops->show_fdinfo(m, sock);
} #else #define sock_show_fdinfo NULL #endif
/* * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear * in the operation structures but are done directly via the socketcall() multiplexor.
*/
/* * Support routines. * Move socket addresses back and forth across the kernel/user * divide and look after the messy bits.
*/
/** * move_addr_to_kernel - copy a socket address into kernel space * @uaddr: Address in user space * @kaddr: Address in kernel space * @ulen: Length in user space * * The address is copied into kernel space. If the provided address is * too long an error code of -EINVAL is returned. If the copy gives * invalid addresses -EFAULT is returned. On a success 0 is returned.
*/
int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr)
{ if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) return -EINVAL; if (ulen == 0) return 0; if (copy_from_user(kaddr, uaddr, ulen)) return -EFAULT; return audit_sockaddr(ulen, kaddr);
}
/** * move_addr_to_user - copy an address to user space * @kaddr: kernel space address * @klen: length of address in kernel * @uaddr: user space address * @ulen: pointer to user length field * * The value pointed to by ulen on entry is the buffer length available. * This is overwritten with the buffer space used. -EINVAL is returned * if an overlong buffer is specified or a negative buffer size. -EFAULT * is returned if either the buffer or the length field are not * accessible. * After copying the data up to the limit the user specifies, the true * length of the data is written over the length limit the user * specified. Zero is returned for a success.
*/
staticint move_addr_to_user(struct sockaddr_storage *kaddr, int klen, void __user *uaddr, int __user *ulen)
{ int err; int len;
BUG_ON(klen > sizeof(struct sockaddr_storage));
err = get_user(len, ulen); if (err) return err; if (len > klen)
len = klen; if (len < 0) return -EINVAL; if (len) { if (audit_sockaddr(klen, kaddr)) return -ENOMEM; if (copy_to_user(uaddr, kaddr, len)) return -EFAULT;
} /* * "fromlen shall refer to the value before truncation.." * 1003.1g
*/ return __put_user(klen, ulen);
}
/* * Obtains the first available file descriptor and sets it up for use. * * These functions create file structures and maps them to fd space * of the current process. On success it returns file descriptor * and file struct implicitly stored in sock->file. * Note that another thread may close file descriptor before we return * from this function. We use the fact that now we do not refer * to socket after mapping. If one day we will need it, this * function will increment ref. count on file by 1. * * In any case returned fd MAY BE not valid! * This race condition is unavoidable * with shared fd spaces, we cannot solve it inside kernel, * but we take care of internal coherence yet.
*/
/** * sock_alloc_file - Bind a &socket to a &file * @sock: socket * @flags: file status flags * @dname: protocol name * * Returns the &file bound with @sock, implicitly storing it * in sock->file. If dname is %NULL, sets to "". * * On failure @sock is released, and an ERR pointer is returned. * * This function uses GFP_KERNEL internally.
*/
/** * sock_from_file - Return the &socket bounded to @file. * @file: file * * On failure returns %NULL.
*/
struct socket *sock_from_file(struct file *file)
{ if (likely(file->f_op == &socket_file_ops)) return file->private_data; /* set in sock_alloc_file */
return NULL;
}
EXPORT_SYMBOL(sock_from_file);
/** * sockfd_lookup - Go from a file number to its socket slot * @fd: file handle * @err: pointer to an error code return * * The file handle passed in is locked and the socket it is bound * to is returned. If an error occurs the err pointer is overwritten * with a negative errno code and NULL is returned. The function checks * for both invalid handles and passing a handle which is not a socket. * * On a success the socket object pointer is returned.
*/
/** * sock_alloc - allocate a socket * * Allocate a new inode and socket object. The two are bound together * and initialised. The socket is then returned. If we are out of inodes * NULL is returned. This functions uses GFP_KERNEL internally.
*/
if (inode)
inode_lock(inode);
ops->release(sock);
sock->sk = NULL; if (inode)
inode_unlock(inode);
sock->ops = NULL;
module_put(owner);
}
if (sock->wq.fasync_list)
pr_err("%s: fasync list not empty!\n", __func__);
if (!sock->file) {
iput(SOCK_INODE(sock)); return;
}
sock->file = NULL;
}
/** * sock_release - close a socket * @sock: socket to close * * The socket is released from the protocol stack if it has a release * callback, and the inode is then released if the socket is bound to * an inode not a file.
*/ void sock_release(struct socket *sock)
{
__sock_release(sock, NULL);
}
EXPORT_SYMBOL(sock_release);
/** * sock_sendmsg - send a message through @sock * @sock: socket * @msg: message to send * * Sends @msg through @sock, passing through LSM. * Returns the number of bytes sent, or an error code.
*/ int sock_sendmsg(struct socket *sock, struct msghdr *msg)
{ struct sockaddr_storage *save_addr = (struct sockaddr_storage *)msg->msg_name; struct sockaddr_storage address; int save_len = msg->msg_namelen; int ret;
if (msg->msg_name) {
memcpy(&address, msg->msg_name, msg->msg_namelen);
msg->msg_name = &address;
}
ret = __sock_sendmsg(sock, msg);
msg->msg_name = save_addr;
msg->msg_namelen = save_len;
return ret;
}
EXPORT_SYMBOL(sock_sendmsg);
/** * kernel_sendmsg - send a message through @sock (kernel-space) * @sock: socket * @msg: message header * @vec: kernel vec * @num: vec array length * @size: total message data size * * Builds the message data with @vec and sends it through @sock. * Returns the number of bytes sent, or an error code.
*/
staticbool skb_is_err_queue(conststruct sk_buff *skb)
{ /* pkt_type of skbs enqueued on the error queue are set to * PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do * in recvmsg, since skbs received on a local socket will never * have a pkt_type of PACKET_OUTGOING.
*/ return skb->pkt_type == PACKET_OUTGOING;
}
/* On transmit, software and hardware timestamps are returned independently. * As the two skb clones share the hardware timestamp, which may be updated * before the software timestamp is received, a hardware TX timestamp may be * returned only if there is no software TX timestamp. Ignore false software * timestamps, which may be made in the __sock_recv_timestamp() call when the * option SO_TIMESTAMP_OLD(NS) is enabled on the socket, even when the skb has a * hardware timestamp.
*/ staticbool skb_is_swtx_tstamp(conststruct sk_buff *skb, int false_tstamp)
{ return skb->tstamp && !false_tstamp && skb_is_err_queue(skb);
}
if (serr->ee.ee_errno != ENOMSG ||
serr->ee.ee_origin != SO_EE_ORIGIN_TIMESTAMPING) returnfalse;
/* software time stamp available and wanted */ if ((tsflags & SOF_TIMESTAMPING_SOFTWARE) && skb->tstamp) returntrue; /* hardware time stamps available and wanted */ return (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
skb_hwtstamps(skb)->hwtstamp;
}
if (tsflags & SOF_TIMESTAMPING_BIND_PHC)
hwtstamp = ptp_convert_timestamp(&hwtstamp,
READ_ONCE(sk->sk_bind_phc)); if (!ktime_to_timespec64_cond(hwtstamp, ts)) return -ENOENT;
return SOF_TIMESTAMPING_TX_HARDWARE;
}
/* * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP)
*/ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
{ int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); struct scm_timestamping_internal tss; int empty = 1, false_tstamp = 0; struct skb_shared_hwtstamps *shhwtstamps =
skb_hwtstamps(skb); int if_index;
ktime_t hwtstamp;
u32 tsflags;
/* Race occurred between timestamp enabling and packet
receiving. Fill in the current time for now. */ if (need_software_tstamp && skb->tstamp == 0) {
__net_timestamp(skb);
false_tstamp = 1;
}
if (need_software_tstamp) { if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { if (new_tstamp) { struct __kernel_sock_timeval tv;
staticvoid sock_recv_mark(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
{ if (sock_flag(sk, SOCK_RCVMARK) && skb) { /* We must use a bounce buffer for CONFIG_HARDENED_USERCOPY=y */
__u32 mark = skb->mark;
static noinline void call_trace_sock_recv_length(struct sock *sk, int ret, int flags)
{
trace_sock_recv_length(sk, ret, flags);
}
staticinlineint sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, int flags)
{ int ret = INDIRECT_CALL_INET(READ_ONCE(sock->ops)->recvmsg,
inet6_recvmsg,
inet_recvmsg, sock, msg,
msg_data_left(msg), flags); if (trace_sock_recv_length_enabled())
call_trace_sock_recv_length(sock->sk, ret, flags); return ret;
}
/** * sock_recvmsg - receive a message from @sock * @sock: socket * @msg: message to receive * @flags: message flags * * Receives @msg from @sock, passing through LSM. Returns the total number * of bytes received, or an error.
*/ int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags)
{ int err = security_socket_recvmsg(sock, msg, msg_data_left(msg), flags);
/** * kernel_recvmsg - Receive a message from a socket (kernel space) * @sock: The socket to receive the message from * @msg: Received message * @vec: Input s/g array for message data * @num: Size of input s/g array * @size: Number of bytes to read * @flags: Message flags (MSG_DONTWAIT, etc...) * * On return the msg structure contains the scatter/gather array passed in the * vec argument. The array is modified so that it consists of the unfilled * portion of the original array. * * The returned value is the total number of bytes received, or an error.
*/
/** * sock_create_lite - creates a socket * @family: protocol family (AF_INET, ...) * @type: communication type (SOCK_STREAM, ...) * @protocol: protocol (0, ...) * @res: new socket * * Creates a new socket and assigns it to @res, passing through LSM. * The new socket initialization is not complete, see kernel_accept(). * Returns 0 or an error. On failure @res is set to %NULL. * This function internally uses GFP_KERNEL.
*/
int sock_create_lite(int family, int type, int protocol, struct socket **res)
{ int err; struct socket *sock = NULL;
err = security_socket_create(family, type, protocol, 1); if (err) goto out;
/* * Update the socket async list * * Fasync_list locking strategy. * * 1. fasync_list is modified only under process context socket lock * i.e. under semaphore. * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) * or under socket lock
*/
lock_sock(sk);
fasync_helper(fd, filp, on, &wq->fasync_list);
if (!wq->fasync_list)
sock_reset_flag(sk, SOCK_FASYNC); else
sock_set_flag(sk, SOCK_FASYNC);
release_sock(sk); return 0;
}
/* This function may be called only under rcu_lock */
int sock_wake_async(struct socket_wq *wq, int how, int band)
{ if (!wq || !wq->fasync_list) return -1;
switch (how) { case SOCK_WAKE_WAITD: if (test_bit(SOCKWQ_ASYNC_WAITDATA, &wq->flags)) break; goto call_kill; case SOCK_WAKE_SPACE: if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags)) break;
fallthrough; case SOCK_WAKE_IO:
call_kill:
kill_fasync(&wq->fasync_list, SIGIO, band); break; case SOCK_WAKE_URG:
kill_fasync(&wq->fasync_list, SIGURG, band);
}
return 0;
}
EXPORT_SYMBOL(sock_wake_async);
/** * __sock_create - creates a socket * @net: net namespace * @family: protocol family (AF_INET, ...) * @type: communication type (SOCK_STREAM, ...) * @protocol: protocol (0, ...) * @res: new socket * @kern: boolean for kernel space sockets * * Creates a new socket and assigns it to @res, passing through LSM. * Returns 0 or an error. On failure @res is set to %NULL. @kern must * be set to true if the socket resides in kernel space. * This function internally uses GFP_KERNEL.
*/
int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern)
{ int err; struct socket *sock; conststruct net_proto_family *pf;
/* * Check protocol is in range
*/ if (family < 0 || family >= NPROTO) return -EAFNOSUPPORT; if (type < 0 || type >= SOCK_MAX) return -EINVAL;
/* Compatibility.
This uglymoron is moved from INET layer to here to avoid deadlock in module load.
*/ if (family == PF_INET && type == SOCK_PACKET) {
pr_info_once("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
current->comm);
family = PF_PACKET;
}
err = security_socket_create(family, type, protocol, kern); if (err) return err;
/* * Allocate the socket and allow the family to set things up. if * the protocol is 0, the family is instructed to select an appropriate * default.
*/
sock = sock_alloc(); if (!sock) {
net_warn_ratelimited("socket: no more sockets\n"); return -ENFILE; /* Not exactly a match, but its the
closest posix thing */
}
sock->type = type;
#ifdef CONFIG_MODULES /* Attempt to load a protocol module if the find failed. * * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user * requested real, full-featured networking support upon configuration. * Otherwise module support will break!
*/ if (rcu_access_pointer(net_families[family]) == NULL)
request_module("net-pf-%d", family); #endif
/* * We will call the ->create function, that possibly is in a loadable * module, so we have to bump that loadable module refcnt first.
*/ if (!try_module_get(pf->owner)) goto out_release;
/* Now protected by module ref count */
rcu_read_unlock();
err = pf->create(net, sock, protocol, kern); if (err < 0) { /* ->create should release the allocated sock->sk object on error * and make sure sock->sk is set to NULL to avoid use-after-free
*/
DEBUG_NET_WARN_ONCE(sock->sk, "%ps must clear sock->sk on failure, family: %d, type: %d, protocol: %d\n",
pf->create, family, type, protocol); goto out_module_put;
}
/* * Now to bump the refcnt of the [loadable] module that owns this * socket at sock_release time we decrement its refcnt.
*/ if (!try_module_get(sock->ops->owner)) goto out_module_busy;
/* * Now that we're done with the ->create function, the [loadable] * module can have its refcnt decremented
*/
module_put(pf->owner);
err = security_socket_post_create(sock, family, type, protocol, kern); if (err) goto out_sock_release;
*res = sock;
/** * sock_create - creates a socket * @family: protocol family (AF_INET, ...) * @type: communication type (SOCK_STREAM, ...) * @protocol: protocol (0, ...) * @res: new socket * * A wrapper around __sock_create(). * Returns 0 or an error. This function internally uses GFP_KERNEL.
*/
int sock_create(int family, int type, int protocol, struct socket **res)
{ return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
}
EXPORT_SYMBOL(sock_create);
/** * sock_create_kern - creates a socket (kernel space) * @net: net namespace * @family: protocol family (AF_INET, ...) * @type: communication type (SOCK_STREAM, ...) * @protocol: protocol (0, ...) * @res: new socket * * A wrapper around __sock_create(). * Returns 0 or an error. This function internally uses GFP_KERNEL.
*/
int sock_create_kern(struct net *net, int family, int type, int protocol, struct socket **res)
{ return __sock_create(net, family, type, protocol, res, 1);
}
EXPORT_SYMBOL(sock_create_kern);
staticstruct socket *__sys_socket_create(int family, int type, int protocol)
{ struct socket *sock; int retval;
struct file *__sys_socket_file(int family, int type, int protocol)
{ struct socket *sock; int flags;
sock = __sys_socket_create(family, type, protocol); if (IS_ERR(sock)) return ERR_CAST(sock);
flags = type & ~SOCK_TYPE_MASK; if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
return sock_alloc_file(sock, flags, NULL);
}
/* A hook for bpf progs to attach to and update socket protocol. * * A static noinline declaration here could cause the compiler to * optimize away the function. A global noinline declaration will * keep the definition, but may optimize away the callsite. * Therefore, __weak is needed to ensure that the call is still * emitted, by telling the compiler that we don't know what the * function might eventually be.
*/
__bpf_hook_start();
__weak noinline int update_socket_protocol(int family, int type, int protocol)
{ return protocol;
}
__bpf_hook_end();
int __sys_socket(int family, int type, int protocol)
{ struct socket *sock; int flags;
int __sys_socketpair(int family, int type, int protocol, int __user *usockvec)
{ struct socket *sock1, *sock2; int fd1, fd2, err; struct file *newfile1, *newfile2; int flags;
flags = type & ~SOCK_TYPE_MASK; if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) return -EINVAL;
type &= SOCK_TYPE_MASK;
/* * reserve descriptors and make sure we won't fail * to return them to userland.
*/
fd1 = get_unused_fd_flags(flags); if (unlikely(fd1 < 0)) return fd1;
/* * Bind a name to a socket. Nothing much to do here since it's * the protocol's responsibility to handle the local address. * * We move the socket address to kernel space before we call * the protocol layer (having also checked the address is ok).
*/
int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{ struct socket *sock; struct sockaddr_storage address; CLASS(fd, f)(fd); int err;
if (fd_empty(f)) return -EBADF;
sock = sock_from_file(fd_file(f)); if (unlikely(!sock)) return -ENOTSOCK;
err = move_addr_to_kernel(umyaddr, addrlen, &address); if (unlikely(err)) return err;
/* * Perform a listen. Basically, we allow the protocol to do anything * necessary for a listen, and if that works, we mark the socket as * ready for listening.
*/ int __sys_listen_socket(struct socket *sock, int backlog)
{ int somaxconn, err;
somaxconn = READ_ONCE(sock_net(sock->sk)->core.sysctl_somaxconn); if ((unsignedint)backlog > somaxconn)
backlog = somaxconn;
/* * For accept, we attempt to create a new socket, set up the link * with the client, wake up the client, then return the new * connected fd. We collect the address of the connector in kernel * space and move it to user at the very end. This is unclean because * we open the socket then return an error. * * 1003.1g adds the ability to recvmsg() to query connection pending * status to recvmsg. We need to add that support in a way thats * clean when we restructure accept also.
*/
int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen, int flags)
{ CLASS(fd, f)(fd);
if (fd_empty(f)) return -EBADF; return __sys_accept4_file(fd_file(f), upeer_sockaddr,
upeer_addrlen, flags);
}
/* * Attempt to connect to a socket with the server address. The address * is in user space so we verify it is OK and move it to kernel space. * * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to * break bindings * * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and * other SEQPACKET protocols that take time to connect() as it doesn't * include the -EINPROGRESS status for such sockets.
*/
int __sys_connect_file(struct file *file, struct sockaddr_storage *address, int addrlen, int file_flags)
{ struct socket *sock; int err;
/* * Send a datagram to a given address. We move the address into kernel * space and check the user space data area is readable before invoking * the protocol.
*/ int __sys_sendto(int fd, void __user *buff, size_t len, unsignedint flags, struct sockaddr __user *addr, int addr_len)
{ struct socket *sock; struct sockaddr_storage address; int err; struct msghdr msg;
err = import_ubuf(ITER_SOURCE, buff, len, &msg.msg_iter); if (unlikely(err)) return err;
CLASS(fd, f)(fd); if (fd_empty(f)) return -EBADF;
sock = sock_from_file(fd_file(f)); if (unlikely(!sock)) return -ENOTSOCK;
/* * Receive a frame from the socket and optionally record the address of the * sender. We verify the buffers are writable and if needed move the * sender address from kernel to user space.
*/ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsignedint flags, struct sockaddr __user *addr, int __user *addr_len)
{ struct sockaddr_storage address; struct msghdr msg = { /* Save some cycles and don't copy the address if not needed */
.msg_name = addr ? (struct sockaddr *)&address : NULL,
}; struct socket *sock; int err, err2;
err = import_ubuf(ITER_DEST, ubuf, size, &msg.msg_iter); if (unlikely(err)) return err;
CLASS(fd, f)(fd);
if (fd_empty(f)) return -EBADF;
sock = sock_from_file(fd_file(f)); if (unlikely(!sock)) return -ENOTSOCK;
int do_sock_setsockopt(struct socket *sock, bool compat, int level, int optname, sockptr_t optval, int optlen)
{ conststruct proto_ops *ops; char *kernel_optval = NULL; int err;
if (optlen < 0) return -EINVAL;
err = security_socket_setsockopt(sock, level, optname); if (err) goto out_put;
if (!compat)
err = BPF_CGROUP_RUN_PROG_SETSOCKOPT(sock->sk, &level, &optname,
optval, &optlen,
&kernel_optval); if (err < 0) goto out_put; if (err > 0) {
err = 0; goto out_put;
}
/* Set a socket option. Because we don't know the option lengths we have * to pass the user mode parameter for the protocols to sort out.
*/ int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval, int optlen)
{
sockptr_t optval = USER_SOCKPTR(user_optval); bool compat = in_compat_syscall(); struct socket *sock; CLASS(fd, f)(fd);
if (fd_empty(f))
return -EBADF;
sock = sock_from_file(fd_file(f));
if (unlikely(!sock))
return -ENOTSOCK;
/*
* Get a socket option. Because we don't know the option lengths we have
* to pass a user mode parameter for the protocols to sort out.
*/
int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
int __user *optlen)
{
struct socket *sock;
CLASS(fd, f)(fd);
if (fd_empty(f))
return -EBADF;
sock = sock_from_file(fd_file(f));
if (unlikely(!sock))
return -ENOTSOCK;
/* A couple of helpful macros for getting the address of the 32/64 bit
* fields which are the same type (int / unsigned) on our platforms.
*/
#define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member)
#define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen)
#define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags)
struct used_address {
struct sockaddr_storage name;
unsigned int name_len;
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.