AF_UNIX SEQPACKET/DGRAM, writable /dev overlay, uevent netlink socket; eudev packages

udevd now starts, reads its rules and listens. Still to come: the sysfs
device tree and writable uevent files so a trigger has something to replay.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
This commit is contained in:
Nexoniarz 2026-10-26 09:51:41 +01:00
commit a9f8cb7e0f
7 changed files with 457 additions and 40 deletions

View file

@ -164,7 +164,7 @@ SYSCALL_DEFINE(socket)
if (type & ~(0xFF | SOCK_CLOEXEC | SOCK_NONBLOCK))
return -EINVAL;
type &= 0xFF;
if (domain == AF_UNIX && type != SOCK_STREAM)
if (domain == AF_UNIX && type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
return -EPROTOTYPE;
if (domain == AF_INET && type != SOCK_STREAM && type != SOCK_DGRAM &&
type != SOCK_RAW)
@ -185,7 +185,7 @@ SYSCALL_DEFINE(socket)
// default rather than departing from it, and programs do write them out:
// toybox's `nc` passes IPPROTO_TCP, and refusing it meant "Protocol not
// supported" for TCP on a system whose whole network is TCP.
if (protocol != 0) {
if (protocol != 0 && domain != AF_NETLINK) {
int redundant =
(domain == AF_INET && type == SOCK_STREAM && protocol == IPPROTO_TCP) ||
(domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP);
@ -270,6 +270,16 @@ SYSCALL_DEFINE(bind)
return sockbind_in(s, ip, port_from_net(port));
}
// sockaddr_nl: family, pad, port id, groups. Only the groups matter here.
if (sock_domain(s) == AF_NETLINK) {
uint groups = 0;
if (ulen < 12)
return -EINVAL;
if (copy_from_user(&groups, uaddr + 8, 4) < 0)
return -EFAULT;
return sock_netlink_bind(s, groups);
}
uint64 key;
if (sun_abstract(uaddr, ulen, &key))
return sockbind_abstract(s, key);
@ -459,15 +469,11 @@ SYSCALL_DEFINE(socketpair)
return -EAFNOSUPPORT;
int sflags = type & (SOCK_CLOEXEC | SOCK_NONBLOCK);
type &= 0xFF;
// Datagram and sequenced-packet pairs are carried as a stream. What they
// are used for between two processes is passing a descriptor or a status
// word -- Rust's process spawning asks for SOCK_SEQPACKET to hear back
// from its child -- and one message at a time is all of that. A reader
// that sends two and wants them kept apart would see them joined.
if (type != SOCK_STREAM && type != 2 /* DGRAM */ && type != 5 /* SEQPACKET */)
// Datagram and sequenced-packet pairs keep message boundaries (kernel/net/unix.c).
if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
return -EPROTOTYPE;
if ((r = sockpair(&a, &b)) < 0)
if ((r = sockpair_type(&a, &b, type)) < 0)
return r;
if ((fd0 = sock_to_fd(a, sflags)) < 0) {
@ -1076,7 +1082,7 @@ SYSCALL_DEFINE(recvmsg)
// one rather than discarding it as Linux would: musl's getifaddrs reads
// in chunks, and this whole queue is one "datagram" only by convention.
int nlret = -1;
if (sock_domain(s) == AF_NETLINK) {
if (sock_domain(s) == AF_NETLINK && !sock_is_packet(s)) {
uint have = socknl_pending(s);
if (have == 0)
return -EAGAIN; // never blocks; see sockread
@ -1127,8 +1133,8 @@ SYSCALL_DEFINE(recvmsg)
return rd;
}
got += rd;
if (rd < len)
break;
if (rd < len || sock_is_packet(s))
break; // one message per call
}
if (nf > 0) {