btio: Rescue lost errorneous numbers

The BT_IO_ERROR_* flags are not used for anything else and we just
loosing errorneous numbers set in the sockets that might be more
useful for handling specific errors.

A use case would be disconnect errors that should not allow BlueZ to
enable auto connections since the connection would never be possible in
some cases.

This patch removes BT_IO_ERROR_* flags and use the errors set in the
sockets instead. Now, the errors passed in connect/disconnect callbacks
should contain proper error numbers passed to them.
diff --git a/btio/btio.c b/btio/btio.c
index e81fb75..f2a9d4b 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -43,7 +43,7 @@
 #endif
 
 #define ERROR_FAILED(gerr, str, err) \
-		g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+		g_set_error(gerr, BT_IO_ERROR, err, \
 				str ": %s (%d)", strerror(err), err)
 
 #define DEFAULT_DEFER_TIMEOUT 30
@@ -124,19 +124,29 @@
 							gpointer user_data)
 {
 	struct accept *accept = user_data;
-	GError *err = NULL;
+	GError *gerr = NULL;
 
 	/* If the user aborted this accept attempt */
 	if ((cond & G_IO_NVAL) || check_nval(io))
 		return FALSE;
 
-	if (cond & (G_IO_HUP | G_IO_ERR))
-		g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
-				"HUP or ERR on socket");
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		int err, sk_err, sock = g_io_channel_unix_get_fd(io);
+		socklen_t len = sizeof(sk_err);
 
-	accept->connect(io, err, accept->user_data);
+		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+			err = -errno;
+		else
+			err = -sk_err;
 
-	g_clear_error(&err);
+		if (err < 0)
+			g_set_error(&gerr, BT_IO_ERROR, -err,
+					"HUP or ERR on socket");
+	}
+
+	accept->connect(io, gerr, accept->user_data);
+
+	g_clear_error(&gerr);
 
 	return FALSE;
 }
@@ -146,14 +156,15 @@
 {
 	struct connect *conn = user_data;
 	GError *gerr = NULL;
+	int err, sk_err, sock;
+	socklen_t len = sizeof(sk_err);
 
 	/* If the user aborted this connect attempt */
 	if ((cond & G_IO_NVAL) || check_nval(io))
 		return FALSE;
 
 	if (cond & G_IO_OUT) {
-		int err, sk_err = 0, sock = g_io_channel_unix_get_fd(io);
-		socklen_t len = sizeof(sk_err);
+		sock = g_io_channel_unix_get_fd(io);
 
 		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
 			err = -errno;
@@ -161,17 +172,24 @@
 			err = -sk_err;
 
 		if (err < 0)
-			g_set_error(&gerr, BT_IO_ERROR,
-					BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
-					strerror(-err), -err);
-	} else if (cond & (G_IO_HUP | G_IO_ERR))
-		g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
-				"HUP or ERR on socket");
+			g_set_error(&gerr, BT_IO_ERROR, -err, "%s (%d)",
+							strerror(-err), -err);
+	} else if (cond & (G_IO_HUP | G_IO_ERR)) {
+		sock = g_io_channel_unix_get_fd(io);
+
+		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+			err = -errno;
+		else
+			err = -sk_err;
+
+		if (err < 0)
+			g_set_error(&gerr, BT_IO_ERROR, -err,
+					"HUP or ERR on socket");
+	}
 
 	conn->connect(io, gerr, conn->user_data);
 
-	if (gerr)
-		g_error_free(gerr);
+	g_clear_error(&gerr);
 
 	return FALSE;
 }
@@ -390,7 +408,7 @@
 	int ret;
 
 	if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
-		g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+		g_set_error(err, BT_IO_ERROR, EINVAL,
 				"Valid security level range is %d-%d",
 				BT_SECURITY_LOW, BT_SECURITY_HIGH);
 		return FALSE;
@@ -764,7 +782,7 @@
 			opts->priority = va_arg(args, int);
 			break;
 		default:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
 			return FALSE;
 		}
@@ -883,7 +901,7 @@
 			bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
 			break;
 		case BT_IO_OPT_DEST_TYPE:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 							"Not implemented");
 			return FALSE;
 		case BT_IO_OPT_DEFER_TIMEOUT:
@@ -961,7 +979,7 @@
 			*(va_arg(args, uint32_t *)) = priority;
 			break;
 		default:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
 			return FALSE;
 		}
@@ -1068,7 +1086,7 @@
 			memcpy(va_arg(args, uint8_t *), dev_class, 3);
 			break;
 		default:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
 			return FALSE;
 		}
@@ -1151,7 +1169,7 @@
 			memcpy(va_arg(args, uint8_t *), dev_class, 3);
 			break;
 		default:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
 			return FALSE;
 		}
@@ -1180,7 +1198,7 @@
 		return sco_get(sock, err, opt1, args);
 	}
 
-	g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+	g_set_error(err, BT_IO_ERROR, EINVAL,
 			"Unknown BtIO type %d", type);
 	return FALSE;
 }
@@ -1245,7 +1263,7 @@
 		return sco_set(sock, opts.mtu, err);
 	}
 
-	g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+	g_set_error(err, BT_IO_ERROR, EINVAL,
 			"Unknown BtIO type %d", type);
 	return FALSE;
 }
@@ -1334,7 +1352,7 @@
 			goto failed;
 		break;
 	default:
-		g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+		g_set_error(err, BT_IO_ERROR, EINVAL,
 				"Unknown BtIO type %d", type);
 		return NULL;
 	}
@@ -1392,14 +1410,14 @@
 		err = sco_connect(sock, &opts.dst);
 		break;
 	default:
-		g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+		g_set_error(gerr, BT_IO_ERROR, EINVAL,
 						"Unknown BtIO type %d", type);
 		return NULL;
 	}
 
 	if (err < 0) {
-		g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
-				"connect: %s (%d)", strerror(-err), -err);
+		g_set_error(gerr, BT_IO_ERROR, -err, "connect: %s (%d)",
+							strerror(-err), -err);
 		g_io_channel_unref(io);
 		return NULL;
 	}
@@ -1421,7 +1439,7 @@
 	gboolean ret;
 
 	if (type == BT_IO_L2RAW) {
-		g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+		g_set_error(err, BT_IO_ERROR, EINVAL,
 				"Server L2CAP RAW sockets not supported");
 		return NULL;
 	}
diff --git a/btio/btio.h b/btio/btio.h
index cf0e070..70b32d6 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -26,13 +26,6 @@
 
 #include <glib.h>
 
-typedef enum {
-	BT_IO_ERROR_DISCONNECTED,
-	BT_IO_ERROR_CONNECT_FAILED,
-	BT_IO_ERROR_FAILED,
-	BT_IO_ERROR_INVALID_ARGS,
-} BtIOError;
-
 #define BT_IO_ERROR bt_io_error_quark()
 
 GQuark bt_io_error_quark(void);