Merge "Handle CMD_IPV6_TETHER_UPDATE in UnavailableState" into main
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 15ad226..5cf5528 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -204,6 +204,7 @@
     use_embedded_native_libs: true,
     privapp_allowlist: ":privapp_allowlist_com.android.tethering",
     apex_available: ["com.android.tethering"],
+    updatable: true,
 }
 
 android_app {
@@ -221,6 +222,7 @@
     lint: {
         error_checks: ["NewApi"],
     },
+    updatable: true,
 }
 
 sdk {
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 5aca642..411971d 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -430,7 +430,7 @@
     // Used to dispatch legacy ConnectivityManager methods that expect tethering to be able to
     // return results and perform operations synchronously.
     // TODO: remove once there are no callers of these legacy methods.
-    private class RequestDispatcher {
+    private static class RequestDispatcher {
         private final ConditionVariable mWaiting;
         public volatile int mRemoteResult;
 
@@ -446,8 +446,8 @@
             mWaiting = new ConditionVariable();
         }
 
-        int waitForResult(final RequestHelper request) {
-            getConnector(c -> request.runRequest(c, mListener));
+        int waitForResult(final RequestHelper request, final TetheringManager mgr) {
+            mgr.getConnector(c -> request.runRequest(c, mListener));
             if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
                 throw new IllegalStateException("Callback timeout");
             }
@@ -603,7 +603,7 @@
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
-        });
+        }, this);
     }
 
     /**
@@ -635,7 +635,7 @@
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
-        });
+        }, this);
     }
 
     /**
@@ -663,7 +663,7 @@
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
-        });
+        }, this);
     }
 
     /**
@@ -1751,7 +1751,7 @@
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
-        });
+        }, this);
 
         return ret == TETHER_ERROR_NO_ERROR;
     }
@@ -1800,6 +1800,6 @@
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
-        });
+        }, this);
     }
 }
diff --git a/bpf/netd/BpfHandler.cpp b/bpf/netd/BpfHandler.cpp
index 9131933..8e4c2c6 100644
--- a/bpf/netd/BpfHandler.cpp
+++ b/bpf/netd/BpfHandler.cpp
@@ -233,7 +233,7 @@
 
 Status BpfHandler::init(const char* cg2_path) {
     // This wait is effectively a no-op on U QPR3+ devices (as netd starts
-    // *after* the synchronous exec_startbpfloader which calls NetBpfLoad)
+    // *after* the synchronous 'exec_start bpfloader' which calls NetBpfLoad)
     // but checking for U QPR3 is hard.
     //
     // Waiting should not be required on U QPR3+ devices,
diff --git a/bpf/progs/offload.c b/bpf/progs/offload.c
index 7e1184d..631908a 100644
--- a/bpf/progs/offload.c
+++ b/bpf/progs/offload.c
@@ -85,9 +85,8 @@
 
     // Since the program never writes via DPA (direct packet access) auto-pull/unclone logic does
     // not trigger and thus we need to manually make sure we can read packet headers via DPA.
-    // Note: this is a blind best effort pull, which may fail or pull less - this doesn't matter.
     // It has to be done early cause it will invalidate any skb->data/data_end derived pointers.
-    try_make_writable(skb, l2_header_size + IP6_HLEN + TCP_HLEN);
+    if (bpf_skb_pull_data(skb, l2_header_size + IP6_HLEN)) return TC_ACT_PIPE;
 
     void* data = (void*)(long)skb->data;
     const void* data_end = (void*)(long)skb->data_end;
@@ -110,6 +109,14 @@
     // If hardware offload is running and programming flows based on conntrack entries,
     // try not to interfere with it.
     if (ip6->nexthdr == IPPROTO_TCP) {
+        // don't need to check return code, as it's effectively checked in the next 'if' below
+        bpf_skb_pull_data(skb, l2_header_size + IP6_HLEN + TCP_HLEN);
+
+        data = (void*)(long)skb->data;
+        data_end = (void*)(long)skb->data_end;
+        eth = is_ethernet ? data : NULL;  // used iff is_ethernet
+        ip6 = is_ethernet ? (void*)(eth + 1) : data;
+
         struct tcphdr* tcph = (void*)(ip6 + 1);
 
         // Make sure we can get at the tcp header
diff --git a/service/ServiceConnectivityResources/Android.bp b/service/ServiceConnectivityResources/Android.bp
index 2621256..be9b2b5 100644
--- a/service/ServiceConnectivityResources/Android.bp
+++ b/service/ServiceConnectivityResources/Android.bp
@@ -33,6 +33,7 @@
         "com.android.tethering",
     ],
     certificate: ":com.android.connectivity.resources.certificate",
+    updatable: true,
 }
 
 android_app_certificate {