{"id":2215689,"url":"http://patchwork.ozlabs.org/api/patches/2215689/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-cifs-client/patch/6778c304d0e4c0de3880e8770cea20d5cf2eed1e.1774410440.git.lucien.xin@gmail.com/","project":{"id":12,"url":"http://patchwork.ozlabs.org/api/projects/12/?format=json","name":"Linux CIFS Client","link_name":"linux-cifs-client","list_id":"linux-cifs.vger.kernel.org","list_email":"linux-cifs@vger.kernel.org","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<6778c304d0e4c0de3880e8770cea20d5cf2eed1e.1774410440.git.lucien.xin@gmail.com>","list_archive_url":null,"date":"2026-03-25T03:47:09","name":"[net-next,v11,04/15] quic: provide family ops for address and protocol","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"c13a25bfdee8ec3b8b4604b577b4ce0c8941aea3","submitter":{"id":61073,"url":"http://patchwork.ozlabs.org/api/people/61073/?format=json","name":"Xin Long","email":"lucien.xin@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-cifs-client/patch/6778c304d0e4c0de3880e8770cea20d5cf2eed1e.1774410440.git.lucien.xin@gmail.com/mbox/","series":[{"id":497380,"url":"http://patchwork.ozlabs.org/api/series/497380/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-cifs-client/list/?series=497380","date":"2026-03-25T03:47:06","name":"net: introduce QUIC infrastructure and core subcomponents","version":11,"mbox":"http://patchwork.ozlabs.org/series/497380/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2215689/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2215689/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <linux-cifs+bounces-10506-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-cifs@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=kHR4bipJ;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=104.64.211.4; helo=sin.lore.kernel.org;\n envelope-from=linux-cifs+bounces-10506-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"kHR4bipJ\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.160.179","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com"],"Received":["from sin.lore.kernel.org (sin.lore.kernel.org [104.64.211.4])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fgXzT1jtvz1y1G\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 14:52:21 +1100 (AEDT)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id 08714301F5D3\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 03:49:40 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id B4E0C19E968;\n\tWed, 25 Mar 2026 03:49:35 +0000 (UTC)","from mail-qt1-f179.google.com (mail-qt1-f179.google.com\n [209.85.160.179])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id B38AB2DECCB\n\tfor <linux-cifs@vger.kernel.org>; Wed, 25 Mar 2026 03:49:33 +0000 (UTC)","by mail-qt1-f179.google.com with SMTP id\n d75a77b69052e-50b2b289925so50607411cf.2\n        for <linux-cifs@vger.kernel.org>;\n Tue, 24 Mar 2026 20:49:33 -0700 (PDT)","from wsfd-netdev58.anl.eng.rdu2.dc.redhat.com ([66.187.232.140])\n        by smtp.gmail.com with ESMTPSA id\n d75a77b69052e-50b36cb2e29sm150093001cf.1.2026.03.24.20.49.29\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Tue, 24 Mar 2026 20:49:31 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1774410575; cv=none;\n b=ilPE5pNH1JZEcP0OdG2MIrmVUkk+A1FGVIq2ixPmU+rwF5lkRsDOJdx0caFyyxkwMPcN8K/kvu+FNBG/pgCwfeUo8BvxN9VGXz9VLYOMS7pBAoyyynogv5JlHuc/BSmL6R20hyaP0rIdOadve7ervI5eNroWXkWX9wwXh/UPiLA=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1774410575; c=relaxed/simple;\n\tbh=DdWhPYVYg1dXbF97aOhWSNizcOULbxASIIHAaNQOK1s=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=p2/7C2u0CWsCEFT0aHvtOCSSZBUMTr0j/RxNMfkwpcGr0VztFqoJcjEpThIuCs/FxSKnea0DZdFzM9bbNwDuDT+IUZMOyoRQcq3Hwd5dzyMwTqdPD5rsaBy9uNfJcXqzwNubypkBnb7rUFvpjo2I+iBTHNA/CfJ0mYtPg87U+1U=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=kHR4bipJ; arc=none smtp.client-ip=209.85.160.179","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1774410573; x=1775015373;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=KJyg8aJcw9LFWPWD7TLzf+mCZGY5VJ1xgQFI8LxqUH4=;\n        b=kHR4bipJAXdwKcqKQLp60zeWR6bQosCQshHN8Hh1gxhWcT1YRaiY6AUl6v6SIJjdjA\n         Ldq2HKfDd1YEN6X9kR1VUQ/wY3UOFU2Or+8iRT8Ull1BImDoSZF8T3fwG+u+0hEl/xHR\n         K7UIBc5dp6WKH5C7uzf9TI4IaqfGaehjqQUP51zT0zJHBRRGckq7Hqq55VtaS7V1aDpu\n         oxq+Jm8m/KQtLWLSHnbbmStC3CoyImsl4HaV3XOFojCjaN3WWKUvETo8ZwI8kUR/P06y\n         4zR8R4gYuCZ0sMIYJsIw4vyH2sGUlZkOYaqjpQZlqY82O7urB+zWaxiri23U8IGN2arx\n         h3AA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1774410573; x=1775015373;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=KJyg8aJcw9LFWPWD7TLzf+mCZGY5VJ1xgQFI8LxqUH4=;\n        b=nzSV4EOqkg36pFnZbZodSs854Y6hrWphAsz4UwCxYbzPpNOQLUJ/dc2ReNYNTTLfqO\n         75AVUAjIwTkGibFc93QXFBrSKnyU0+sufaDYPKsWQrnieV+jFoieoJj8JYXJITtYAA+f\n         zRgmbWcmocmFD+kbU5h94vYxS2Qr3r+s+05v6RFH28WixJ36Nv6XB2y4ymZAGIZihen0\n         tuy/V7lfEaEFJu1Rz+S7KHW7IQffmkBTqAdxzRBnpnjE1hirHEtZwGnTkCAT1WGGtSUp\n         /GbaC7pslYzZwP/dBCu2aG0epQsKvJQTghOOPCaJSZ+9SPiaVHSgKIrtJ0Hg5kkYnDPK\n         kGzA==","X-Forwarded-Encrypted":"i=1;\n AJvYcCXK5S2Qj92ZkoYhOkbwywyCorXlFJKTuUUqgnAkQaCAtc2jp39qMewkfL1GwTIyFsSb51JdAUCeD4h3@vger.kernel.org","X-Gm-Message-State":"AOJu0Yx09aJbMTV9yyxCw8Z1h5CNLqUQU7LYiG+Cu2wFPHd9o3cdQvXX\n\t2SlavzQjObnzQApVc3+k/KYOYLhHnKQI+kVF53YmCM/EJ0m0cu10rZaH","X-Gm-Gg":"ATEYQzzGRJJHeVWhUCKL6w/0IhE9TZOPkLK7NQgovD3o1KD3SghhyzznjpScDXZYjlm\n\tjZ9wp7DzZIeqEeGsgPPD0x5lor4MYauNjE2D4V3uKk2f4aSZqhdYwBRmdXBFo3fal9wtIWlqH+5\n\tlEx41t+e/NRG42XBAlvMVDXlnzdkp7Qi57/gxMYw9BFlGZkeyoAfs8Fnr2mcbdVi6rdIv8GqKZb\n\tssgTcLO+54y904EU93qXZZTKuWQn1ZDZnM6US++tHBTLLWOX89FtLQkmJZnkDBL9y1snn3Ah31t\n\t5m3K8S2hL6HHS12o0sRBNAqY3SYWOPIlrMbKBY0JXF2wweNGoQHvgmbcdSW0ECzfm6ZWoZjX7wR\n\tI549msWsgHlnqAc0f9DUElWnyIIxS7M3kjoFCSv5HPK2nPVvCE6RLxlpObJ6ERDFXedlvJyIshA\n\t8Hb5yCnfRSRPLYxVtiVgqjZr90QhGMFmosi+9ippZ3BtFi5G4kzhTD2MKuRoT6A8IiqREODkR2w\n\t7LjBUC8CS+XefjorsCYBmS55UfWXJDQYDOjREXevuKrXA7mMR6lqyhqfQpeZrIxtcbB6MGH1/v7","X-Received":"by 2002:a05:622a:1997:b0:509:18f4:6dba with SMTP id\n d75a77b69052e-50b80e72436mr32169601cf.62.1774410572600;\n        Tue, 24 Mar 2026 20:49:32 -0700 (PDT)","From":"Xin Long <lucien.xin@gmail.com>","To":"network dev <netdev@vger.kernel.org>,\n\tquic@lists.linux.dev","Cc":"davem@davemloft.net,\n\tkuba@kernel.org,\n\tEric Dumazet <edumazet@google.com>,\n\tPaolo Abeni <pabeni@redhat.com>,\n\tSimon Horman <horms@kernel.org>,\n\tStefan Metzmacher <metze@samba.org>,\n\tMoritz Buhl <mbuhl@openbsd.org>,\n\tTyler Fanelli <tfanelli@redhat.com>,\n\tPengtao He <hepengtao@xiaomi.com>,\n\tThomas Dreibholz <dreibh@simula.no>,\n\tlinux-cifs@vger.kernel.org,\n\tSteve French <smfrench@gmail.com>,\n\tNamjae Jeon <linkinjeon@kernel.org>,\n\tPaulo Alcantara <pc@manguebit.com>,\n\tTom Talpey <tom@talpey.com>,\n\tkernel-tls-handshake@lists.linux.dev,\n\tChuck Lever <chuck.lever@oracle.com>,\n\tJeff Layton <jlayton@kernel.org>,\n\tSteve Dickson <steved@redhat.com>,\n\tHannes Reinecke <hare@suse.de>,\n\tAlexander Aring <aahringo@redhat.com>,\n\tDavid Howells <dhowells@redhat.com>,\n\tMatthieu Baerts <matttbe@kernel.org>,\n\tJohn Ericson <mail@johnericson.me>,\n\tCong Wang <xiyou.wangcong@gmail.com>,\n\t\"D . Wythe\" <alibuda@linux.alibaba.com>,\n\tJason Baron <jbaron@akamai.com>,\n\tilliliti <illiliti@protonmail.com>,\n\tSabrina Dubroca <sd@queasysnail.net>,\n\tMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>,\n\tDaniel Stenberg <daniel@haxx.se>,\n\tAndy Gospodarek <andrew.gospodarek@broadcom.com>,\n\t\"Marc E . Fiuczynski\" <marc@fiuczynski.com>","Subject":"[PATCH net-next v11 04/15] quic: provide family ops for address and\n protocol","Date":"Tue, 24 Mar 2026 23:47:09 -0400","Message-ID":"\n <6778c304d0e4c0de3880e8770cea20d5cf2eed1e.1774410440.git.lucien.xin@gmail.com>","X-Mailer":"git-send-email 2.47.1","In-Reply-To":"<cover.1774410440.git.lucien.xin@gmail.com>","References":"<cover.1774410440.git.lucien.xin@gmail.com>","Precedence":"bulk","X-Mailing-List":"linux-cifs@vger.kernel.org","List-Id":"<linux-cifs.vger.kernel.org>","List-Subscribe":"<mailto:linux-cifs+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-cifs+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"Introduce QUIC address and protocol family operations to handle IPv4/IPv6\nspecifics consistently, similar to SCTP. The new quic_family.{c,h} provide\nhelpers for routing, skb transmit handling, address parsing and comparison\nand UDP socket config initializing etc.\n\nThis consolidates protocol-family logic and enables cleaner dual-stack\nsupport in the QUIC socket implementation.\n\nSigned-off-by: Xin Long <lucien.xin@gmail.com>\nAcked-by: Paolo Abeni <pabeni@redhat.com>\n---\nv2:\n  - Add more checks for addrs in .get_user_addr() and .get_pref_addr().\n  - Consider sk_bound_dev_if in .udp_conf_init() and .flow_route() to\n    support vrf.\nv3:\n  - Remove quic_addr_family/proto_ops abstraction; use if statements to\n    reduce indirect call overhead (suggested by Paolo).\n  - quic_v6_set_sk_addr(): add quic_v6_copy_sk_addr() helper to avoid\n    duplicate code (noted by Paolo).\n  - quic_v4_flow_route(): use flowi4_dscp per latest net-next changes.\nv4:\n  - Remove unnecessary _fl variable from flow_route() functions (noted\n    by Paolo).\n  - Fix coding style of ?: operator (noted by Paolo).\nv5:\n  - Remove several unused functions from this patch series (suggested by Paolo):\n    * quic_seq_dump_addr()\n    * quic_get_msg_ecn()\n    * quic_get_user_addr()\n    * quic_get_pref_addr()\n    * quic_set_pref_addr()\n    * quic_set_sk_addr()\n    * quic_set_sk_ecn()\n  - Replace the sa->v4/v6.sin_family checks with quic_v4/v6_is_any_addr()\n    in quic_v4/v6_flow_route() (suggested by Paolo).\n  - Introduce quic_v4_match_v6_addr() to simplify family-mismatch checks\n    between sk and addr in quic_v6_cmp_sk_addr() (notied by Paolo).\nv6:\n  - Use udp_hdr(skb) to access UDP header in quic_v4/6_get_msg_addrs(), as\n    transport_header is no longer reset for QUIC.\nv10:\n  - Fix argument types passed to ip6_dst_store() in quic_v6_flow_route().\nv11:\n  - Set maximum line length to 80 characters.\n  - Change return type of quic_is_any_addr() to bool.\n  - Call local_bh_disable() in quic_lower_xmit() because\n    udp(6)_tunnel_xmit_skb() requires a non-preemptible context.\n  - Return a negative errno (-EINVAL) instead of 1 in\n    quic_v4/v6_get_mtu_info().\n---\n net/quic/Makefile   |   2 +-\n net/quic/family.c   | 402 ++++++++++++++++++++++++++++++++++++++++++++\n net/quic/family.h   |  39 +++++\n net/quic/protocol.c |   2 +-\n net/quic/socket.c   |   6 +-\n net/quic/socket.h   |   1 +\n 6 files changed, 448 insertions(+), 4 deletions(-)\n create mode 100644 net/quic/family.c\n create mode 100644 net/quic/family.h","diff":"diff --git a/net/quic/Makefile b/net/quic/Makefile\nindex e0067272de7d..13bf4a4e5442 100644\n--- a/net/quic/Makefile\n+++ b/net/quic/Makefile\n@@ -5,4 +5,4 @@\n \n obj-$(CONFIG_IP_QUIC) += quic.o\n \n-quic-y := common.o protocol.o socket.o\n+quic-y := common.o family.o protocol.o socket.o\ndiff --git a/net/quic/family.c b/net/quic/family.c\nnew file mode 100644\nindex 000000000000..c16fffb35d9e\n--- /dev/null\n+++ b/net/quic/family.c\n@@ -0,0 +1,402 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/* QUIC kernel implementation\n+ * (C) Copyright Red Hat Corp. 2023\n+ *\n+ * This file is part of the QUIC kernel implementation\n+ *\n+ * Initialization/cleanup for QUIC protocol support.\n+ *\n+ * Written or modified by:\n+ *    Xin Long <lucien.xin@gmail.com>\n+ */\n+\n+#include <net/inet_common.h>\n+#include <net/udp_tunnel.h>\n+#include <linux/icmp.h>\n+\n+#include \"common.h\"\n+#include \"family.h\"\n+\n+static bool quic_v4_is_any_addr(union quic_addr *addr)\n+{\n+\treturn addr->v4.sin_addr.s_addr == htonl(INADDR_ANY);\n+}\n+\n+static bool quic_v6_is_any_addr(union quic_addr *addr)\n+{\n+\treturn ipv6_addr_any(&addr->v6.sin6_addr);\n+}\n+\n+static void quic_v4_udp_conf_init(struct sock *sk, struct udp_port_cfg *conf,\n+\t\t\t\t  union quic_addr *a)\n+{\n+\tconf->family = AF_INET;\n+\tconf->local_ip.s_addr = a->v4.sin_addr.s_addr;\n+\tconf->local_udp_port = a->v4.sin_port;\n+\tconf->use_udp6_rx_checksums = true;\n+\tconf->bind_ifindex = sk->sk_bound_dev_if;\n+}\n+\n+static void quic_v6_udp_conf_init(struct sock *sk, struct udp_port_cfg *conf,\n+\t\t\t\t  union quic_addr *a)\n+{\n+\tconf->family = AF_INET6;\n+\tconf->local_ip6 = a->v6.sin6_addr;\n+\tconf->local_udp_port = a->v6.sin6_port;\n+\tconf->use_udp6_rx_checksums = true;\n+\tconf->ipv6_v6only = ipv6_only_sock(sk);\n+\tconf->bind_ifindex = sk->sk_bound_dev_if;\n+}\n+\n+static int quic_v4_flow_route(struct sock *sk, union quic_addr *da,\n+\t\t\t      union quic_addr *sa, struct flowi *fl)\n+{\n+\tstruct flowi4 *fl4;\n+\tstruct rtable *rt;\n+\n+\tif (__sk_dst_check(sk, 0))\n+\t\treturn 1;\n+\n+\tmemset(fl, 0x00, sizeof(*fl));\n+\tfl4 = &fl->u.ip4;\n+\tfl4->saddr = sa->v4.sin_addr.s_addr;\n+\tfl4->fl4_sport = sa->v4.sin_port;\n+\tfl4->daddr = da->v4.sin_addr.s_addr;\n+\tfl4->fl4_dport = da->v4.sin_port;\n+\tfl4->flowi4_proto = IPPROTO_UDP;\n+\tfl4->flowi4_oif = sk->sk_bound_dev_if;\n+\n+\tfl4->flowi4_scope = ip_sock_rt_scope(sk);\n+\tfl4->flowi4_dscp = inet_sk_dscp(inet_sk(sk));\n+\n+\trt = ip_route_output_key(sock_net(sk), fl4);\n+\tif (IS_ERR(rt))\n+\t\treturn PTR_ERR(rt);\n+\n+\tif (quic_v4_is_any_addr(sa)) {\n+\t\tsa->v4.sin_family = AF_INET;\n+\t\tsa->v4.sin_addr.s_addr = fl4->saddr;\n+\t}\n+\tsk_setup_caps(sk, &rt->dst);\n+\treturn 0;\n+}\n+\n+static int quic_v6_flow_route(struct sock *sk, union quic_addr *da,\n+\t\t\t      union quic_addr *sa, struct flowi *fl)\n+{\n+\tstruct ipv6_pinfo *np = inet6_sk(sk);\n+\tstruct ip6_flowlabel *flowlabel;\n+\tstruct dst_entry *dst;\n+\tstruct flowi6 *fl6;\n+\n+\tif (__sk_dst_check(sk, np->dst_cookie))\n+\t\treturn 1;\n+\n+\tmemset(fl, 0x00, sizeof(*fl));\n+\tfl6 = &fl->u.ip6;\n+\tfl6->saddr = sa->v6.sin6_addr;\n+\tfl6->fl6_sport = sa->v6.sin6_port;\n+\tfl6->daddr = da->v6.sin6_addr;\n+\tfl6->fl6_dport = da->v6.sin6_port;\n+\tfl6->flowi6_proto = IPPROTO_UDP;\n+\tfl6->flowi6_oif = sk->sk_bound_dev_if;\n+\n+\tif (inet6_test_bit(SNDFLOW, sk)) {\n+\t\tfl6->flowlabel = (da->v6.sin6_flowinfo & IPV6_FLOWINFO_MASK);\n+\t\tif (fl6->flowlabel & IPV6_FLOWLABEL_MASK) {\n+\t\t\tflowlabel = fl6_sock_lookup(sk, fl6->flowlabel);\n+\t\t\tif (IS_ERR(flowlabel))\n+\t\t\t\treturn -EINVAL;\n+\t\t\tfl6_sock_release(flowlabel);\n+\t\t}\n+\t}\n+\n+\tdst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, NULL);\n+\tif (IS_ERR(dst))\n+\t\treturn PTR_ERR(dst);\n+\n+\tif (quic_v6_is_any_addr(sa)) {\n+\t\tsa->v6.sin6_family = AF_INET6;\n+\t\tsa->v6.sin6_addr = fl6->saddr;\n+\t}\n+\tip6_dst_store(sk, dst, false, false);\n+\treturn 0;\n+}\n+\n+static void quic_v4_lower_xmit(struct sock *sk, struct sk_buff *skb,\n+\t\t\t       struct flowi *fl)\n+{\n+\tstruct quic_skb_cb *cb = QUIC_SKB_CB(skb);\n+\tu8 tos = (inet_sk(sk)->tos | cb->ecn), ttl;\n+\tstruct flowi4 *fl4 = &fl->u.ip4;\n+\tstruct dst_entry *dst;\n+\t__be16 df = 0;\n+\n+\tpr_debug(\"%s: skb: %p, len: %d, num: %llu, %pI4:%d -> %pI4:%d\\n\",\n+\t\t __func__, skb, skb->len, cb->number, &fl4->saddr,\n+\t\t ntohs(fl4->fl4_sport), &fl4->daddr, ntohs(fl4->fl4_dport));\n+\n+\tdst = sk_dst_get(sk);\n+\tif (!dst) {\n+\t\tkfree_skb(skb);\n+\t\treturn;\n+\t}\n+\tif (ip_dont_fragment(sk, dst) && !skb->ignore_df)\n+\t\tdf = htons(IP_DF);\n+\n+\tttl = (u8)ip4_dst_hoplimit(dst);\n+\tudp_tunnel_xmit_skb((struct rtable *)dst, sk, skb, fl4->saddr,\n+\t\t\t    fl4->daddr, tos, ttl, df, fl4->fl4_sport,\n+\t\t\t    fl4->fl4_dport, false, false, 0);\n+}\n+\n+static void quic_v6_lower_xmit(struct sock *sk, struct sk_buff *skb,\n+\t\t\t       struct flowi *fl)\n+{\n+\tstruct quic_skb_cb *cb = QUIC_SKB_CB(skb);\n+\tu8 tc = (inet6_sk(sk)->tclass | cb->ecn), ttl;\n+\tstruct flowi6 *fl6 = &fl->u.ip6;\n+\tstruct dst_entry *dst;\n+\t__be32 label;\n+\n+\tpr_debug(\"%s: skb: %p, len: %d, num: %llu, %pI6c:%d -> %pI6c:%d\\n\",\n+\t\t __func__, skb, skb->len, cb->number, &fl6->saddr,\n+\t\t ntohs(fl6->fl6_sport), &fl6->daddr, ntohs(fl6->fl6_dport));\n+\n+\tdst = sk_dst_get(sk);\n+\tif (!dst) {\n+\t\tkfree_skb(skb);\n+\t\treturn;\n+\t}\n+\n+\tttl = (u8)ip6_dst_hoplimit(dst);\n+\tlabel = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true,\n+\t\t\t\t   fl6);\n+\tudp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, &fl6->daddr, tc,\n+\t\t\t     ttl, label, fl6->fl6_sport, fl6->fl6_dport, false,\n+\t\t\t     0);\n+}\n+\n+static void quic_v4_get_msg_addrs(struct sk_buff *skb, union quic_addr *da,\n+\t\t\t\t  union quic_addr *sa)\n+{\n+\tstruct udphdr *uh = udp_hdr(skb);\n+\n+\tsa->v4.sin_family = AF_INET;\n+\tsa->v4.sin_port = uh->source;\n+\tsa->v4.sin_addr.s_addr = ip_hdr(skb)->saddr;\n+\n+\tda->v4.sin_family = AF_INET;\n+\tda->v4.sin_port = uh->dest;\n+\tda->v4.sin_addr.s_addr = ip_hdr(skb)->daddr;\n+}\n+\n+static void quic_v6_get_msg_addrs(struct sk_buff *skb, union quic_addr *da,\n+\t\t\t\t  union quic_addr *sa)\n+{\n+\tstruct udphdr *uh = udp_hdr(skb);\n+\n+\tsa->v6.sin6_family = AF_INET6;\n+\tsa->v6.sin6_port = uh->source;\n+\tsa->v6.sin6_addr = ipv6_hdr(skb)->saddr;\n+\n+\tda->v6.sin6_family = AF_INET6;\n+\tda->v6.sin6_port = uh->dest;\n+\tda->v6.sin6_addr = ipv6_hdr(skb)->daddr;\n+}\n+\n+static int quic_v4_get_mtu_info(struct sk_buff *skb, u32 *info)\n+{\n+\tstruct icmphdr *hdr;\n+\n+\thdr = (struct icmphdr *)(skb_network_header(skb) -\n+\t      sizeof(struct icmphdr));\n+\tif (hdr->type == ICMP_DEST_UNREACH && hdr->code == ICMP_FRAG_NEEDED) {\n+\t\t*info = ntohs(hdr->un.frag.mtu);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Defer other types' processing to UDP error handler. */\n+\treturn -EINVAL;\n+}\n+\n+static int quic_v6_get_mtu_info(struct sk_buff *skb, u32 *info)\n+{\n+\tstruct icmp6hdr *hdr;\n+\n+\thdr = (struct icmp6hdr *)(skb_network_header(skb) -\n+\t      sizeof(struct icmp6hdr));\n+\tif (hdr->icmp6_type == ICMPV6_PKT_TOOBIG) {\n+\t\t*info = ntohl(hdr->icmp6_mtu);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Defer other types' processing to UDP error handler. */\n+\treturn -EINVAL;\n+}\n+\n+static bool quic_v4_cmp_sk_addr(struct sock *sk, union quic_addr *a,\n+\t\t\t\tunion quic_addr *addr)\n+{\n+\tif (a->v4.sin_port != addr->v4.sin_port)\n+\t\treturn false;\n+\tif (a->v4.sin_family != addr->v4.sin_family)\n+\t\treturn false;\n+\tif (a->v4.sin_addr.s_addr == htonl(INADDR_ANY) ||\n+\t    addr->v4.sin_addr.s_addr == htonl(INADDR_ANY))\n+\t\treturn true;\n+\treturn a->v4.sin_addr.s_addr == addr->v4.sin_addr.s_addr;\n+}\n+\n+static bool quic_v4_match_v6_addr(union quic_addr *a4, union quic_addr *a6)\n+{\n+\tif (ipv6_addr_any(&a6->v6.sin6_addr))\n+\t\treturn true;\n+\tif (ipv6_addr_v4mapped(&a6->v6.sin6_addr) &&\n+\t    a6->v6.sin6_addr.s6_addr32[3] == a4->v4.sin_addr.s_addr)\n+\t\treturn true;\n+\treturn false;\n+}\n+\n+static bool quic_v6_cmp_sk_addr(struct sock *sk, union quic_addr *a,\n+\t\t\t\tunion quic_addr *addr)\n+{\n+\tif (a->v4.sin_port != addr->v4.sin_port)\n+\t\treturn false;\n+\n+\tif (a->sa.sa_family == AF_INET && addr->sa.sa_family == AF_INET) {\n+\t\tif (a->v4.sin_addr.s_addr == htonl(INADDR_ANY) ||\n+\t\t    addr->v4.sin_addr.s_addr == htonl(INADDR_ANY))\n+\t\t\treturn true;\n+\t\treturn a->v4.sin_addr.s_addr == addr->v4.sin_addr.s_addr;\n+\t}\n+\n+\tif (a->sa.sa_family != addr->sa.sa_family) {\n+\t\tif (ipv6_only_sock(sk))\n+\t\t\treturn false;\n+\t\tif (a->sa.sa_family == AF_INET)\n+\t\t\treturn quic_v4_match_v6_addr(a, addr);\n+\t\treturn quic_v4_match_v6_addr(addr, a);\n+\t}\n+\n+\tif (ipv6_addr_any(&a->v6.sin6_addr) ||\n+\t    ipv6_addr_any(&addr->v6.sin6_addr))\n+\t\treturn true;\n+\treturn ipv6_addr_equal(&a->v6.sin6_addr, &addr->v6.sin6_addr);\n+}\n+\n+static int quic_v4_get_sk_addr(struct socket *sock, struct sockaddr *uaddr,\n+\t\t\t       int peer)\n+{\n+\treturn inet_getname(sock, uaddr, peer);\n+}\n+\n+static int quic_v6_get_sk_addr(struct socket *sock, struct sockaddr *uaddr,\n+\t\t\t       int peer)\n+{\n+\tunion quic_addr *a = quic_addr(uaddr);\n+\tint ret;\n+\n+\tret = inet6_getname(sock, uaddr, peer);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (a->sa.sa_family == AF_INET6 &&\n+\t    ipv6_addr_v4mapped(&a->v6.sin6_addr)) {\n+\t\ta->v4.sin_family = AF_INET;\n+\t\ta->v4.sin_port = a->v6.sin6_port;\n+\t\ta->v4.sin_addr.s_addr = a->v6.sin6_addr.s6_addr32[3];\n+\t}\n+\n+\tif (a->sa.sa_family == AF_INET) {\n+\t\tmemset(a->v4.sin_zero, 0, sizeof(a->v4.sin_zero));\n+\t\treturn sizeof(struct sockaddr_in);\n+\t}\n+\treturn sizeof(struct sockaddr_in6);\n+}\n+\n+#define quic_af_ipv4(a)\t\t((a)->sa.sa_family == AF_INET)\n+\n+u32 quic_encap_len(union quic_addr *a)\n+{\n+\treturn (quic_af_ipv4(a) ? sizeof(struct iphdr) :\n+\t\t\t\t  sizeof(struct ipv6hdr)) +\n+\t       sizeof(struct udphdr);\n+}\n+\n+bool quic_is_any_addr(union quic_addr *a)\n+{\n+\treturn quic_af_ipv4(a) ? quic_v4_is_any_addr(a) :\n+\t\t\t\t quic_v6_is_any_addr(a);\n+}\n+\n+void quic_udp_conf_init(struct sock *sk, struct udp_port_cfg *conf,\n+\t\t\tunion quic_addr *a)\n+{\n+\tquic_af_ipv4(a) ? quic_v4_udp_conf_init(sk, conf, a) :\n+\t\t\t  quic_v6_udp_conf_init(sk, conf, a);\n+}\n+\n+int quic_flow_route(struct sock *sk, union quic_addr *da, union quic_addr *sa,\n+\t\t    struct flowi *fl)\n+{\n+\treturn quic_af_ipv4(da) ? quic_v4_flow_route(sk, da, sa, fl) :\n+\t\t\t\t  quic_v6_flow_route(sk, da, sa, fl);\n+}\n+\n+void quic_lower_xmit(struct sock *sk, struct sk_buff *skb, union quic_addr *da,\n+\t\t     struct flowi *fl)\n+{\n+\tlocal_bh_disable();\n+\tquic_af_ipv4(da) ? quic_v4_lower_xmit(sk, skb, fl) :\n+\t\t\t   quic_v6_lower_xmit(sk, skb, fl);\n+\tlocal_bh_enable();\n+}\n+\n+#define quic_skb_ipv4(skb)\t(ip_hdr(skb)->version == 4)\n+\n+void quic_get_msg_addrs(struct sk_buff *skb, union quic_addr *da,\n+\t\t\tunion quic_addr *sa)\n+{\n+\tmemset(sa, 0, sizeof(*sa));\n+\tmemset(da, 0, sizeof(*da));\n+\tquic_skb_ipv4(skb) ? quic_v4_get_msg_addrs(skb, da, sa) :\n+\t\t\t     quic_v6_get_msg_addrs(skb, da, sa);\n+}\n+\n+int quic_get_mtu_info(struct sk_buff *skb, u32 *info)\n+{\n+\treturn quic_skb_ipv4(skb) ? quic_v4_get_mtu_info(skb, info) :\n+\t\t\t\t    quic_v6_get_mtu_info(skb, info);\n+}\n+\n+#define quic_pf_ipv4(sk)\t((sk)->sk_family == PF_INET)\n+\n+bool quic_cmp_sk_addr(struct sock *sk, union quic_addr *a,\n+\t\t      union quic_addr *addr)\n+{\n+\treturn quic_pf_ipv4(sk) ? quic_v4_cmp_sk_addr(sk, a, addr) :\n+\t\t\t\t  quic_v6_cmp_sk_addr(sk, a, addr);\n+}\n+\n+int quic_get_sk_addr(struct socket *sock, struct sockaddr *a, bool peer)\n+{\n+\treturn quic_pf_ipv4(sock->sk) ? quic_v4_get_sk_addr(sock, a, peer) :\n+\t\t\t\t\tquic_v6_get_sk_addr(sock, a, peer);\n+}\n+\n+int quic_common_setsockopt(struct sock *sk, int level, int optname,\n+\t\t\t   sockptr_t optval, unsigned int optlen)\n+{\n+\treturn quic_pf_ipv4(sk) ?\n+\t       ip_setsockopt(sk, level, optname, optval, optlen) :\n+\t       ipv6_setsockopt(sk, level, optname, optval, optlen);\n+}\n+\n+int quic_common_getsockopt(struct sock *sk, int level, int optname,\n+\t\t\t   char __user *optval, int __user *optlen)\n+{\n+\treturn quic_pf_ipv4(sk) ?\n+\t       ip_getsockopt(sk, level, optname, optval, optlen) :\n+\t       ipv6_getsockopt(sk, level, optname, optval, optlen);\n+}\ndiff --git a/net/quic/family.h b/net/quic/family.h\nnew file mode 100644\nindex 000000000000..a68356c1ffb5\n--- /dev/null\n+++ b/net/quic/family.h\n@@ -0,0 +1,39 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/* QUIC kernel implementation\n+ * (C) Copyright Red Hat Corp. 2023\n+ *\n+ * This file is part of the QUIC kernel implementation\n+ *\n+ * Written or modified by:\n+ *    Xin Long <lucien.xin@gmail.com>\n+ */\n+\n+#define QUIC_PORT_LEN\t\t2\n+#define QUIC_ADDR4_LEN\t\t4\n+#define QUIC_ADDR6_LEN\t\t16\n+\n+#define QUIC_PREF_ADDR_LEN \\\n+\t(QUIC_ADDR4_LEN + QUIC_PORT_LEN + QUIC_ADDR6_LEN + QUIC_PORT_LEN)\n+\n+bool quic_is_any_addr(union quic_addr *a);\n+u32 quic_encap_len(union quic_addr *a);\n+\n+void quic_lower_xmit(struct sock *sk, struct sk_buff *skb, union quic_addr *da,\n+\t\t     struct flowi *fl);\n+int quic_flow_route(struct sock *sk, union quic_addr *da, union quic_addr *sa,\n+\t\t    struct flowi *fl);\n+void quic_udp_conf_init(struct sock *sk, struct udp_port_cfg *conf,\n+\t\t\tunion quic_addr *a);\n+\n+void quic_get_msg_addrs(struct sk_buff *skb, union quic_addr *da,\n+\t\t\tunion quic_addr *sa);\n+int quic_get_mtu_info(struct sk_buff *skb, u32 *info);\n+\n+bool quic_cmp_sk_addr(struct sock *sk, union quic_addr *a,\n+\t\t      union quic_addr *addr);\n+int quic_get_sk_addr(struct socket *sock, struct sockaddr *a, bool peer);\n+\n+int quic_common_setsockopt(struct sock *sk, int level, int optname,\n+\t\t\t   sockptr_t optval, unsigned int optlen);\n+int quic_common_getsockopt(struct sock *sk, int level, int optname,\n+\t\t\t   char __user *optval, int __user *optlen);\ndiff --git a/net/quic/protocol.c b/net/quic/protocol.c\nindex 807e2a228ba8..c247f00f7ddc 100644\n--- a/net/quic/protocol.c\n+++ b/net/quic/protocol.c\n@@ -47,7 +47,7 @@ static int quic_inet_listen(struct socket *sock, int backlog)\n static int quic_inet_getname(struct socket *sock, struct sockaddr *uaddr,\n \t\t\t     int peer)\n {\n-\treturn -EOPNOTSUPP;\n+\treturn quic_get_sk_addr(sock, uaddr, peer);\n }\n \n static __poll_t quic_inet_poll(struct file *file, struct socket *sock,\ndiff --git a/net/quic/socket.c b/net/quic/socket.c\nindex 6a742fe57df1..f1181215ebbf 100644\n--- a/net/quic/socket.c\n+++ b/net/quic/socket.c\n@@ -117,7 +117,8 @@ static int quic_setsockopt(struct sock *sk, int level, int optname,\n \t\t\t   sockptr_t optval, unsigned int optlen)\n {\n \tif (level != SOL_QUIC)\n-\t\treturn -EOPNOTSUPP;\n+\t\treturn quic_common_setsockopt(sk, level, optname, optval,\n+\t\t\t\t\t      optlen);\n \n \treturn quic_do_setsockopt(sk, optname, optval, optlen);\n }\n@@ -132,7 +133,8 @@ static int quic_getsockopt(struct sock *sk, int level, int optname,\n \t\t\t   char __user *optval, int __user *optlen)\n {\n \tif (level != SOL_QUIC)\n-\t\treturn -EOPNOTSUPP;\n+\t\treturn quic_common_getsockopt(sk, level, optname, optval,\n+\t\t\t\t\t      optlen);\n \n \treturn quic_do_getsockopt(sk, optname, USER_SOCKPTR(optval),\n \t\t\t\t  USER_SOCKPTR(optlen));\ndiff --git a/net/quic/socket.h b/net/quic/socket.h\nindex 9a2f4b851676..0aa642e3b0ae 100644\n--- a/net/quic/socket.h\n+++ b/net/quic/socket.h\n@@ -11,6 +11,7 @@\n #include <net/udp_tunnel.h>\n \n #include \"common.h\"\n+#include \"family.h\"\n \n #include \"protocol.h\"\n \n","prefixes":["net-next","v11","04/15"]}