Implement the "select network" fwmark command.

Change-Id: Id4a49eb288b18022d53014d1ae2211ed7d1099a6
diff --git a/server/FwmarkServer.cpp b/server/FwmarkServer.cpp
index 56127ca..605e724 100644
--- a/server/FwmarkServer.cpp
+++ b/server/FwmarkServer.cpp
@@ -20,6 +20,7 @@
 #include "FwmarkCommand.h"
 #include "NetworkController.h"
 #include "PermissionsController.h"
+#include "resolv_netid.h"
 
 #include <sys/socket.h>
 #include <unistd.h>
@@ -87,7 +88,7 @@
     }
 
     if (*fd < 0) {
-        errno = ENOENT;
+        errno = EBADF;
         return;
     }
 
@@ -97,6 +98,8 @@
         return;
     }
 
+    fwmark.permission = mPermissionsController->getPermissionForUser(client->getUid());
+
     switch (command.cmdId) {
         case FwmarkCommand::ON_ACCEPT: {
             // Called after a socket accept(). The kernel would've marked the netId into the socket
@@ -118,8 +121,26 @@
         }
 
         case FwmarkCommand::SELECT_NETWORK: {
-            // set socket mark
-            // TODO
+            fwmark.netId = command.netId;
+            if (command.netId == NETID_UNSET) {
+                fwmark.explicitlySelected = false;
+            } else {
+                fwmark.explicitlySelected = true;
+                // If the socket already has the protectedFromVpn bit set, don't reset it, because
+                // non-CONNECTIVITY_INTERNAL apps (e.g.: VpnService) may also protect sockets.
+                if (fwmark.permission & PERMISSION_CONNECTIVITY_INTERNAL) {
+                    fwmark.protectedFromVpn = true;
+                }
+                if (!mNetworkController->isValidNetwork(command.netId)) {
+                    errno = ENONET;
+                    return;
+                }
+                if (!mPermissionsController->isUserPermittedOnNetwork(client->getUid(),
+                                                                      command.netId)) {
+                    errno = EPERM;
+                    return;
+                }
+            }
             break;
         }
 
@@ -136,8 +157,6 @@
         }
     }
 
-    fwmark.permission = mPermissionsController->getPermissionForUser(client->getUid());
-
     if (setsockopt(*fd, SOL_SOCKET, SO_MARK, &fwmark.intValue, sizeof(fwmark.intValue)) == -1) {
         return;
     }