The l4 protocol trackers are invoked via indirect call: l4proto->packet().
With one exception (gre), all l4trackers are builtin, so we can make
.packet optional and use a direct call for most protocols.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
                              struct sk_buff *skb,
                              unsigned int dataoff,
                              const struct nf_hook_state *state);
+
+int nf_conntrack_icmp_packet(struct nf_conn *ct,
+                            struct sk_buff *skb,
+                            enum ip_conntrack_info ctinfo,
+                            const struct nf_hook_state *state);
+
+int nf_conntrack_icmpv6_packet(struct nf_conn *ct,
+                              struct sk_buff *skb,
+                              enum ip_conntrack_info ctinfo,
+                              const struct nf_hook_state *state);
+
+int nf_conntrack_udp_packet(struct nf_conn *ct,
+                           struct sk_buff *skb,
+                           unsigned int dataoff,
+                           enum ip_conntrack_info ctinfo,
+                           const struct nf_hook_state *state);
+int nf_conntrack_udplite_packet(struct nf_conn *ct,
+                               struct sk_buff *skb,
+                               unsigned int dataoff,
+                               enum ip_conntrack_info ctinfo,
+                               const struct nf_hook_state *state);
+int nf_conntrack_tcp_packet(struct nf_conn *ct,
+                           struct sk_buff *skb,
+                           unsigned int dataoff,
+                           enum ip_conntrack_info ctinfo,
+                           const struct nf_hook_state *state);
+int nf_conntrack_dccp_packet(struct nf_conn *ct,
+                            struct sk_buff *skb,
+                            unsigned int dataoff,
+                            enum ip_conntrack_info ctinfo,
+                            const struct nf_hook_state *state);
+int nf_conntrack_sctp_packet(struct nf_conn *ct,
+                            struct sk_buff *skb,
+                            unsigned int dataoff,
+                            enum ip_conntrack_info ctinfo,
+                            const struct nf_hook_state *state);
+
 /* Existing built-in generic protocol */
 extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic;
 
 
        return ret;
 }
 
+/* Returns verdict for packet, or -1 for invalid. */
+static int nf_conntrack_handle_packet(struct nf_conn *ct,
+                                     struct sk_buff *skb,
+                                     unsigned int dataoff,
+                                     enum ip_conntrack_info ctinfo,
+                                     const struct nf_hook_state *state)
+{
+       switch (nf_ct_protonum(ct)) {
+       case IPPROTO_TCP:
+               return nf_conntrack_tcp_packet(ct, skb, dataoff,
+                                              ctinfo, state);
+       case IPPROTO_UDP:
+               return nf_conntrack_udp_packet(ct, skb, dataoff,
+                                              ctinfo, state);
+       case IPPROTO_ICMP:
+               return nf_conntrack_icmp_packet(ct, skb, ctinfo, state);
+       case IPPROTO_ICMPV6:
+               return nf_conntrack_icmpv6_packet(ct, skb, ctinfo, state);
+#ifdef CONFIG_NF_CT_PROTO_UDPLITE
+       case IPPROTO_UDPLITE:
+               return nf_conntrack_udplite_packet(ct, skb, dataoff,
+                                                  ctinfo, state);
+#endif
+#ifdef CONFIG_NF_CT_PROTO_SCTP
+       case IPPROTO_SCTP:
+               return nf_conntrack_sctp_packet(ct, skb, dataoff,
+                                               ctinfo, state);
+#endif
+#ifdef CONFIG_NF_CT_PROTO_DCCP
+       case IPPROTO_DCCP:
+               return nf_conntrack_dccp_packet(ct, skb, dataoff,
+                                               ctinfo, state);
+#endif
+       }
+
+       WARN_ON_ONCE(1);
+       return -NF_ACCEPT;
+}
+
 unsigned int
 nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state)
 {
                goto out;
        }
 
-       ret = l4proto->packet(ct, skb, dataoff, ctinfo, state);
+       if (l4proto->packet)
+               ret = l4proto->packet(ct, skb, dataoff, ctinfo, state);
+       else
+               ret = nf_conntrack_handle_packet(ct, skb, dataoff, ctinfo, state);
+
        if (ret <= 0) {
                /* Invalid: inverse of the return code tells
                 * the netfilter core what to do */
 
        return true;
 }
 
-static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb,
-                      unsigned int dataoff, enum ip_conntrack_info ctinfo,
-                      const struct nf_hook_state *state)
+int nf_conntrack_dccp_packet(struct nf_conn *ct, struct sk_buff *skb,
+                            unsigned int dataoff,
+                            enum ip_conntrack_info ctinfo,
+                            const struct nf_hook_state *state)
 {
        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
        struct dccp_hdr _dh, *dh;
 
 const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp = {
        .l4proto                = IPPROTO_DCCP,
-       .packet                 = dccp_packet,
        .can_early_drop         = dccp_can_early_drop,
 #ifdef CONFIG_NF_CONNTRACK_PROCFS
        .print_conntrack        = dccp_print_conntrack,
 
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
-static int icmp_packet(struct nf_conn *ct,
-                      struct sk_buff *skb,
-                      unsigned int dataoff,
-                      enum ip_conntrack_info ctinfo,
-                      const struct nf_hook_state *state)
+int nf_conntrack_icmp_packet(struct nf_conn *ct,
+                            struct sk_buff *skb,
+                            enum ip_conntrack_info ctinfo,
+                            const struct nf_hook_state *state)
 {
        /* Do not immediately delete the connection after the first
           successful reply to avoid excessive conntrackd traffic
        .l4proto                = IPPROTO_ICMP,
        .pkt_to_tuple           = icmp_pkt_to_tuple,
        .invert_tuple           = icmp_invert_tuple,
-       .packet                 = icmp_packet,
-       .destroy                = NULL,
-       .me                     = NULL,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .tuple_to_nlattr        = icmp_tuple_to_nlattr,
        .nlattr_tuple_size      = icmp_nlattr_tuple_size,
 
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
-static int icmpv6_packet(struct nf_conn *ct,
-                        struct sk_buff *skb,
-                        unsigned int dataoff,
-                        enum ip_conntrack_info ctinfo,
-                        const struct nf_hook_state *state)
+int nf_conntrack_icmpv6_packet(struct nf_conn *ct,
+                              struct sk_buff *skb,
+                              enum ip_conntrack_info ctinfo,
+                              const struct nf_hook_state *state)
 {
        unsigned int *timeout = nf_ct_timeout_lookup(ct);
        static const u8 valid_new[] = {
        .l4proto                = IPPROTO_ICMPV6,
        .pkt_to_tuple           = icmpv6_pkt_to_tuple,
        .invert_tuple           = icmpv6_invert_tuple,
-       .packet                 = icmpv6_packet,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .tuple_to_nlattr        = icmpv6_tuple_to_nlattr,
        .nlattr_tuple_size      = icmpv6_nlattr_tuple_size,
 
 }
 
 /* Returns verdict for packet, or -NF_ACCEPT for invalid. */
-static int sctp_packet(struct nf_conn *ct,
-                      struct sk_buff *skb,
-                      unsigned int dataoff,
-                      enum ip_conntrack_info ctinfo,
-                      const struct nf_hook_state *state)
+int nf_conntrack_sctp_packet(struct nf_conn *ct,
+                            struct sk_buff *skb,
+                            unsigned int dataoff,
+                            enum ip_conntrack_info ctinfo,
+                            const struct nf_hook_state *state)
 {
        enum sctp_conntrack new_state, old_state;
        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 #ifdef CONFIG_NF_CONNTRACK_PROCFS
        .print_conntrack        = sctp_print_conntrack,
 #endif
-       .packet                 = sctp_packet,
        .can_early_drop         = sctp_can_early_drop,
-       .me                     = THIS_MODULE,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .nlattr_size            = SCTP_NLATTR_SIZE,
        .to_nlattr              = sctp_to_nlattr,
 
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
-static int tcp_packet(struct nf_conn *ct,
-                     struct sk_buff *skb,
-                     unsigned int dataoff,
-                     enum ip_conntrack_info ctinfo,
-                     const struct nf_hook_state *state)
+int nf_conntrack_tcp_packet(struct nf_conn *ct,
+                           struct sk_buff *skb,
+                           unsigned int dataoff,
+                           enum ip_conntrack_info ctinfo,
+                           const struct nf_hook_state *state)
 {
        struct net *net = nf_ct_net(ct);
        struct nf_tcp_net *tn = nf_tcp_pernet(net);
 #ifdef CONFIG_NF_CONNTRACK_PROCFS
        .print_conntrack        = tcp_print_conntrack,
 #endif
-       .packet                 = tcp_packet,
        .can_early_drop         = tcp_can_early_drop,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .to_nlattr              = tcp_to_nlattr,
 
 }
 
 /* Returns verdict for packet, and may modify conntracktype */
-static int udp_packet(struct nf_conn *ct,
-                     struct sk_buff *skb,
-                     unsigned int dataoff,
-                     enum ip_conntrack_info ctinfo,
-                     const struct nf_hook_state *state)
+int nf_conntrack_udp_packet(struct nf_conn *ct,
+                           struct sk_buff *skb,
+                           unsigned int dataoff,
+                           enum ip_conntrack_info ctinfo,
+                           const struct nf_hook_state *state)
 {
        unsigned int *timeouts;
 
 }
 
 /* Returns verdict for packet, and may modify conntracktype */
-static int udplite_packet(struct nf_conn *ct,
-                         struct sk_buff *skb,
-                         unsigned int dataoff,
-                         enum ip_conntrack_info ctinfo,
-                         const struct nf_hook_state *state)
+int nf_conntrack_udplite_packet(struct nf_conn *ct,
+                               struct sk_buff *skb,
+                               unsigned int dataoff,
+                               enum ip_conntrack_info ctinfo,
+                               const struct nf_hook_state *state)
 {
        unsigned int *timeouts;
 
 {
        .l4proto                = IPPROTO_UDP,
        .allow_clash            = true,
-       .packet                 = udp_packet,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 {
        .l4proto                = IPPROTO_UDPLITE,
        .allow_clash            = true,
-       .packet                 = udplite_packet,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,