diff --git a/.gitignore b/.gitignore
index 31fbd9ea0167665e3270149e99faca295aee5c10..0c47a9507a03cca914a75c91dd05994561b41c4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ dongle_apn
 dongle_pin
 dongle_network
 ipkg*
+test-parse*
diff --git a/Makefile b/Makefile
index 929c380927cbc3ab677b77db1b823e08b13ed70d..7e3cb732c1f1bc48232bfd00f64fc21cb75eeb56 100644
--- a/Makefile
+++ b/Makefile
@@ -2,14 +2,7 @@ CC		= gcc
 CFLAGS		= -g -Wall
 LIBS		= -ljson-c -lubox -lubus -luci -lcurl -lmobile
 
-all: libmobile1 libmobile2# common dongle_apn dongle_pin dongle_network
-
-
-#gcc -shared -o libhello.so -fPIC hello.c
-#MOBJS		= libmobile.so
-#MSRCS		= libmobile.c
-#libmobile: ${MOBJS}
-#	${CC} -shared -o ${MOBJS} -fPIC ${MSRCS}
+all: libmobile1 libmobile2 common dongle_apn dongle_pin dongle_network dongle
 
 MOBJS		= libmobile.o
 MSRCS		= libmobile.c
@@ -21,25 +14,27 @@ MSRCS		= libmobile.c
 libmobile2: ${MOBJS}
 	${CC} ${MOBJS} -shared -o libmobile.so
 
-#COBJS		= common.o
-#CSRCS		= common.c
-#common: ${COBJS}
-#	${CC} -c ${CSRCS} -o ${COBJS}
-#
-#DAOBJS		= dongle_apn.o
-#DASRCS		= dongle_apn.c
-#dongle_apn: ${DAOBJS}
-#	 ${CC} ${CFLAGS} ${DAOBJS} ${COBJS} -o dongle_apn  ${LIBS}
-#
-#DPOBJS		= dongle_pin.o
-#DPSRCS		= dongle_pin.c
-#dongle_pin: ${DPOBJS}
-#	 ${CC} ${CFLAGS} ${DPOBJS} ${COBJS} -o dongle_pin  ${LIBS}
-#
-#DNOBJS		= dongle_network.o
-#DNSRCS		= dongle_network.c
-#dongle_network: ${DNOBJS}
-#	 ${CC} ${CFLAGS} ${DNOBJS} ${COBJS} -o dongle_network  ${LIBS}
+common: ${COBJS}
+	${CC} -c ${CSRCS} -o ${COBJS}
+
+DAOBJS = dongle_apn.o
+DASRCS = dongle_apn.c
+dongle_apn: ${DAOBJS}
+	${CC} -c ${CFLAGS} ${DASRCS} ${COBJS} -o ${DAOBJS} -L . ${LIBS} #${MOBJS}
+
+DPOBJS = dongle_pin.o
+DPSRCS = dongle_pin.c
+dongle_pin: ${DPOBJS}
+	${CC} -c ${CFLAGS} ${DPSRCS} ${COBJS} -o ${DPOBJS} -L . ${LIBS} #${MOBJS}
+
+DNOBJS = dongle_network.o
+DNSRCS = dongle_network.c
+dongle_network: ${DNOBJS}
+	${CC} -c ${CFLAGS} ${DNSRCS} ${COBJS} -o ${DNOBJS} -L . ${LIBS} #${MOBJS}
+
+dongle: dongle.o
+	${CC} ${CFLAGS} dongle.o ${COBJS} ${DNOBJS} ${DPOBJS} ${DAOBJS} -o dongle -L . ${LIBS} #${MOBJS}
+
 clean:
 	rm -f dongle_apn dongle_pin dongle_network *.o *.so
 
diff --git a/common.c b/common.c
index 0353e8bdbb10556fe8d4a6d958f705c1509e38ba..2a0ede4d1b0f55da98d9b44d76b4a2e25a087197 100644
--- a/common.c
+++ b/common.c
@@ -1,35 +1,16 @@
 #include "common.h"
 
-int parse_and_print(char *dongle_response, struct ubus_context *ctx, struct ubus_request_data *req)
-{
-	if (!dongle_response) {
-		DEBUG("no respose!\n");
-		goto fail;
-	}
-	struct json_object *parsed_response = json_tokener_parse(dongle_response);
-
-	if (!parsed_response) {
-		DEBUG("No valid JSON, failed parsing!\n");
-		goto free_response;
-	}
-	write_to_ubus(parsed_response, ctx, req);
-
-	json_object_put(parsed_response);
-free_response:
-	free(dongle_response);
-fail:
-	return 0;
-}
-
-int write_to_ubus(struct json_object *parsed_response, struct ubus_context *ctx, struct ubus_request_data *req)
+int print_to_ubus(struct json_object *parsed_response, struct ubus_context *ctx, struct ubus_request_data *req)
 {
 	struct blob_buf bb;
+
 	memset(&bb, 0, sizeof(struct blob_buf));
 	blob_buf_init(&bb, 0);
 	bb = json_to_blob(parsed_response, bb);
 	ubus_send_reply(ctx, req, bb.head);
 	blob_buf_free(&bb);
-	//json_object_put(parsed_response);
+
+	json_object_put(parsed_response);
 	return 0;
 }
 
@@ -37,8 +18,10 @@ struct blob_buf json_to_blob(struct json_object *response, struct blob_buf bb)
 {
 	void *arr, *obj;
 	int i;
+
 	json_object_object_foreach(response, key, val) {
 		int val_type = json_object_get_type(val);
+
 		switch (val_type) {
 		case json_type_int:
 			blobmsg_add_u32(&bb, key, json_object_get_int(val));
diff --git a/common.h b/common.h
index 3d918702beab9664007fdc3973a4dd80ff1bc265..3129be7189449711d2ce8dfe9b7020b35b2f5db3 100644
--- a/common.h
+++ b/common.h
@@ -1,38 +1,27 @@
 #ifndef COMMON_H
 #define COMMON_H
-#define DEBUG(message, ...)						\
-	do											\
-	{											\
-		fprintf(stdout, "\n(DEBUG)\t");			\
-		fprintf(stdout, message, ##__VA_ARGS__);\
-	} while (0)
-#include "libtrace.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <limits.h>
+#include <libubox/list.h>
+
 #include <libmobile.h>
 #include <json-c/json.h>
 #include <string.h>
 #include <libubox/blobmsg.h>
 #include <libubus.h>
-/**
- * Function: parse_and_print
- *
- * Parses a string to its corresponding JSON format, if available, then writes it on ubus through <write_to_ubus>.
- *
- * IMPORTANT NOTE
- * Will free the input string!
- *
- * Parameters:
- * 		dongle_response - A string of JSON format that should be printed on ubus.
- * 		ctx - Ubus context containing connection.
- * 		req - Information for from the ubus request.
- *
- * Returns:
- * 		0 On success.
- * 		-1 On failure.
- */
-int parse_and_print(char *dongle_response, struct ubus_context *ctx, struct ubus_request_data *req);
 
 /**
- * Function: write_to_ubus
+ * Function: print_to_ubus
  *
  * Prints a json_object pointer's json structure to ubus.
  *
@@ -45,7 +34,7 @@ int parse_and_print(char *dongle_response, struct ubus_context *ctx, struct ubus
  * 		0 On success.
  * 		-1 On failure.
  */
-int write_to_ubus(struct json_object *parsed_response, struct ubus_context *ctx, struct ubus_request_data *req);
+int print_to_ubus(struct json_object *parsed_response, struct ubus_context *ctx, struct ubus_request_data *req);
 
 /**
  * Function: json_to_blob
diff --git a/dongle.c b/dongle.c
new file mode 100644
index 0000000000000000000000000000000000000000..6fc47a41c8de3e5f5314ff8c88b98034e3a88ebd
--- /dev/null
+++ b/dongle.c
@@ -0,0 +1,28 @@
+#include "common.h"
+#include "dongle_apn.h"
+#include "dongle_pin.h"
+#include "dongle_network.h"
+
+struct ubus_context *ctx;
+
+void init_ubus(void)
+{
+	ctx = ubus_connect(NULL);
+	if (!ctx) {
+		perror("ubus");
+		exit(1);
+	}
+	ubus_add_uloop(ctx);
+}
+
+int main(int argc, char **argv)
+{
+	uloop_init();
+	init_ubus();
+	expose_apn_object(ctx);
+	expose_pin_object(ctx);
+	expose_network_object(ctx);
+	uloop_run();
+
+	return 0;
+}
\ No newline at end of file
diff --git a/dongle_apn.c b/dongle_apn.c
new file mode 100644
index 0000000000000000000000000000000000000000..6273ac25490af321bd2d17852b6168bcf36e6be5
--- /dev/null
+++ b/dongle_apn.c
@@ -0,0 +1,181 @@
+#include "dongle_apn.h"
+
+enum {
+	APN_NAME,
+	__APN_MAX,
+};
+
+enum {
+	PROFILE_NAME,
+	WAN_APN,
+	PDP_TYPE,
+	__CREATE_MAX,
+};
+
+const struct blobmsg_policy create_apn_policy[__CREATE_MAX] = {
+	[PROFILE_NAME] = {.name = "profile_name", .type = BLOBMSG_TYPE_STRING},
+	[WAN_APN] = {.name = "wan_apn", .type = BLOBMSG_TYPE_STRING},
+	[PDP_TYPE] = {.name = "pdp_type", .type = BLOBMSG_TYPE_STRING},
+};
+
+const struct blobmsg_policy apn_policy[__APN_MAX] = {
+	[APN_NAME] = {.name = "profile_name", .type = BLOBMSG_TYPE_STRING},
+};
+
+int list_apn_profiles(struct ubus_context *ctx, struct ubus_object *obj,
+			   struct ubus_request_data *req, const char *method,
+			   struct blob_attr *msg)
+{
+	struct json_object *response = mobile_get_apn_profiles();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int delete_apn_profile(struct ubus_context *ctx, struct ubus_object *obj,
+			   struct ubus_request_data *req, const char *method,
+			   struct blob_attr *msg)
+{
+	struct blob_attr *tb[__APN_MAX];
+	char *name; //what is max available name length in dongle?
+	struct json_object *response;
+
+	blobmsg_parse(apn_policy, __APN_MAX, tb, blob_data(msg), blob_len(msg));
+	if (!tb[APN_NAME])
+		goto fail_argument;
+
+	name = (char *)blobmsg_data(tb[APN_NAME]);
+	if (strlen(name) == 0) {
+		debug_print("Empty is not a name!\n");
+		goto fail_argument;
+	} else if (strlen(name) > 1023) {
+		debug_print("name too long!\n");
+		goto fail_argument;
+	}
+
+	response = mobile_delete_apn(name);
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_argument:
+	return UBUS_STATUS_INVALID_ARGUMENT;
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int set_apn_profile(struct ubus_context *ctx, struct ubus_object *obj,
+					   struct ubus_request_data *req, const char *method,
+					   struct blob_attr *msg)
+{
+	struct blob_attr *tb[__APN_MAX];
+	char *name;
+	struct json_object *response;
+
+	blobmsg_parse(apn_policy, __APN_MAX, tb, blob_data(msg), blob_len(msg));
+	if (!tb[APN_NAME])
+		goto fail_argument;
+
+	name = (char *)blobmsg_data(tb[APN_NAME]);
+	if (strlen(name) == 0) {
+		debug_print("Empty is not a name!\n");
+		goto fail_argument;
+	} else if (strlen(name) > 1023) {
+		debug_print("name too long!\n");
+		goto fail_argument;
+	}
+
+	response = mobile_set_apn_profile(name);
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_argument:
+	return UBUS_STATUS_INVALID_ARGUMENT;
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int create_apn_profile(struct ubus_context *ctx, struct ubus_object *obj,
+				struct ubus_request_data *req, const char *method,
+				struct blob_attr *msg)
+{
+	struct blob_attr *tb[__CREATE_MAX];
+	char *profile_name, *wan_apn, *pdp_type; //what is max available name length in dongle?
+	struct json_object *response;
+
+	blobmsg_parse(create_apn_policy, __CREATE_MAX, tb, blob_data(msg), blob_len(msg));
+	if (!tb[PROFILE_NAME] || !tb[WAN_APN] || !tb[PDP_TYPE]) {
+		debug_print("Need to provide all arguments!\n");
+		goto fail_argument;
+	}
+
+	profile_name = (char *)blobmsg_data(tb[PROFILE_NAME]);
+	wan_apn = (char *)blobmsg_data(tb[WAN_APN]);
+	pdp_type = (char *)blobmsg_data(tb[PDP_TYPE]);
+	if (strlen(profile_name) > 1023 || strlen(wan_apn) > 1023 || strlen(pdp_type) > 1023) {
+		debug_print("input may be max 1023 characters!\n");
+		goto fail_argument;
+	} else if (strlen(profile_name) <= 0 || strlen(wan_apn) <= 0 || strlen(pdp_type) <= 0) {
+		debug_print("Empty string is not a valid input!\n");
+		goto fail_argument;
+	}
+
+	response = mobile_create_apn_profile(profile_name, wan_apn, pdp_type);
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_argument:
+	return UBUS_STATUS_INVALID_ARGUMENT;
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int show_current_apn(struct ubus_context *ctx, struct ubus_object *obj,
+				 struct ubus_request_data *req, const char *method,
+				 struct blob_attr *msg)
+{
+	struct json_object *response = mobile_get_wan_apn();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+struct ubus_method apn_object_methods[] = {
+	UBUS_METHOD_NOARG("list", list_apn_profiles),
+	UBUS_METHOD("create", create_apn_profile, create_apn_policy),
+	UBUS_METHOD("delete", delete_apn_profile, apn_policy),
+	UBUS_METHOD("set_profile", set_apn_profile, apn_policy),
+	UBUS_METHOD_NOARG("current", show_current_apn),
+};
+
+struct ubus_object_type apn_object_type = UBUS_OBJECT_TYPE("dongle", apn_object_methods);
+
+struct ubus_object apn_object = {
+	.name = "dongle.apn",
+	.type = &apn_object_type,
+	.methods = apn_object_methods,
+	.n_methods = ARRAY_SIZE(apn_object_methods),
+};
+
+int expose_apn_object(struct ubus_context *ctx)
+{
+	int rv;
+
+	rv = ubus_add_object(ctx, &apn_object);
+	if (rv) {
+		debug_print("failed to add dongle.pin to ubus!\n");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/dongle_apn.h b/dongle_apn.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b6a0bfabcde5d865718efed3090ffcb115472b5
--- /dev/null
+++ b/dongle_apn.h
@@ -0,0 +1,6 @@
+#ifndef APN_H
+#define APN_H
+#include "common.h"
+
+int expose_apn_object(struct ubus_context *ctx);
+#endif
\ No newline at end of file
diff --git a/dongle_network.c b/dongle_network.c
new file mode 100644
index 0000000000000000000000000000000000000000..da9a9449b8a5ef3f5911fca6c2b5bfd08a8f8b0e
--- /dev/null
+++ b/dongle_network.c
@@ -0,0 +1,130 @@
+#include "dongle_network.h"
+
+int get_signal_strength(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct json_object *response = mobile_get_rssi();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+int connect_network(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct json_object *response = mobile_connect_network();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int disconnect(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct json_object *response = mobile_disconnect_network();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int modem_state(struct ubus_context *ctx, struct ubus_object *obj,
+			   struct ubus_request_data *req, const char *method,
+			   struct blob_attr *msg)
+{
+	struct json_object *response = mobile_get_modem_state();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int enable_roaming(struct ubus_context *ctx, struct ubus_object *obj,
+			   struct ubus_request_data *req, const char *method,
+			   struct blob_attr *msg)
+{
+	struct json_object *response = mobile_enable_roaming();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int disable_roaming(struct ubus_context *ctx, struct ubus_object *obj,
+				   struct ubus_request_data *req, const char *method,
+				   struct blob_attr *msg)
+{
+	struct json_object *response = mobile_disable_roaming();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int roam_status(struct ubus_context *ctx, struct ubus_object *obj,
+					struct ubus_request_data *req, const char *method,
+					struct blob_attr *msg)
+{
+	struct json_object *response = mobile_get_roam_status();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+struct ubus_method network_object_methods[] = {
+	UBUS_METHOD_NOARG("signal_strength", get_signal_strength),
+	UBUS_METHOD_NOARG("connect", connect_network),
+	UBUS_METHOD_NOARG("disconnect", disconnect),
+	UBUS_METHOD_NOARG("modem_state", modem_state),
+	UBUS_METHOD_NOARG("enable_roaming", enable_roaming),
+	UBUS_METHOD_NOARG("disable_roaming", disable_roaming),
+	UBUS_METHOD_NOARG("roam_status", roam_status),
+};
+
+struct ubus_object_type network_object_type = UBUS_OBJECT_TYPE("dongle", network_object_methods);
+
+struct ubus_object network_object = {
+	.name = "dongle.network",
+	.type = &network_object_type,
+	.methods = network_object_methods,
+	.n_methods = ARRAY_SIZE(network_object_methods),
+};
+
+int expose_network_object(struct ubus_context *ctx)
+{
+	int rv;
+
+	rv = ubus_add_object(ctx, &network_object);
+	if (rv) {
+		debug_print("failed to add dongle.pin to ubus!\n");
+		return -1;
+	}
+
+	return 0;
+}
\ No newline at end of file
diff --git a/dongle_network.h b/dongle_network.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6c3e9044518eef0c5cc2bf6b0111b3640c8ab0d
--- /dev/null
+++ b/dongle_network.h
@@ -0,0 +1,6 @@
+#ifndef NETWORK_H
+#define NETWORK_H
+#include "common.h"
+
+int expose_network_object(struct ubus_context *ctx);
+#endif
\ No newline at end of file
diff --git a/dongle_pin.c b/dongle_pin.c
new file mode 100644
index 0000000000000000000000000000000000000000..61057949dbe8d8199b56c55c4784896c237f3cfa
--- /dev/null
+++ b/dongle_pin.c
@@ -0,0 +1,349 @@
+#include "dongle_pin.h"
+
+static int isdigits(const char *pin);
+static int validate_pin_format(char *pin);
+
+enum {
+	NEW_PIN,
+	CURRENT_PIN,
+	__SET_PIN_MAX,
+};
+
+enum {
+	PIN,
+	__PIN_MAX,
+};
+
+const struct blobmsg_policy set_pin_policy[__SET_PIN_MAX] = {
+	[NEW_PIN] = {.name = "new_pin", .type = BLOBMSG_TYPE_STRING},
+	[CURRENT_PIN] = {.name = "current_pin", .type = BLOBMSG_TYPE_STRING},
+};
+
+const struct blobmsg_policy pin_policy[__PIN_MAX] = {
+	[PIN] = {.name = "pin", .type = BLOBMSG_TYPE_STRING},
+};
+
+
+static int isdigits(const char *pin)
+{
+	while (*pin) {
+		if (isdigit(*pin++) == 0)
+			return false;
+	}
+	return true;
+}
+
+static int validate_pin_format(char *pin)
+{
+	if (!isdigits(pin)) {
+		debug_print("Please enter digits only!\n");
+		goto fail;
+	} else if (strlen(pin) > 8 || strlen(pin) < 4) {
+		debug_print("Please enter between 4 to 8 digits!\n");
+		goto fail;
+	} else if (atoi(pin) == 0) {
+		debug_print("0000 is not a valid pin! Lowest available is 0001\n");
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -1;
+}
+
+int set_pin(struct ubus_context *ctx, struct ubus_object *obj,
+				 struct ubus_request_data *req, const char *method,
+				 struct blob_attr *msg)
+{
+	struct blob_attr *tb[__SET_PIN_MAX];
+	char *new_pin, *current_pin;
+	int rv;
+	struct json_object *response, *rv_json;
+
+	blobmsg_parse(set_pin_policy, __SET_PIN_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[NEW_PIN] && !tb[CURRENT_PIN]) {
+		debug_print("Please enter both a new pin and old pin!\n");
+		goto fail_input;
+	}
+	new_pin = (char *)blobmsg_data(tb[NEW_PIN]);
+	current_pin = (char *)blobmsg_data(tb[CURRENT_PIN]);
+
+	rv = validate_pin_format(new_pin);
+	if (rv > 0) {
+		debug_print("invalid pin format\n");
+		goto fail_input;
+	}
+
+	rv = validate_pin_format(current_pin);
+	if (rv > 0) {
+		debug_print("invalid pin format\n");
+		goto fail_input;
+	}
+
+	response = mobile_get_pin_status();
+	if (!response) {
+		debug_print("error getting pin_status\n");
+		goto fail_data;
+	}
+
+	json_object_object_get_ex(response, "pin_status", &rv_json);
+	if (!rv_json) {
+		debug_print("no pin_status available\n");
+		goto fail_result;
+	}
+
+	/* Enable PIN if it is disabled */
+	if (!json_object_get_int(rv_json)) {
+		json_object_put(response);
+
+		response = mobile_enable_pin(current_pin);
+		if (!response) {
+			debug_print("error enabling pin!\n");
+			goto fail_unknown;
+		}
+
+		json_object_object_get_ex(response, "result", &rv_json);
+		if (!rv_json) {
+			debug_print("error getting result!\n");
+			goto fail_result;
+		}
+
+		if (strncmp(json_object_get_string(rv_json), "failure", strlen("failure")) == 0) {
+			debug_print("Incorrect pin!\n");
+			goto incorrect_pin;
+		}
+	}
+
+	json_object_put(response);
+	response = mobile_set_pin(current_pin, new_pin);
+	if (!response) {
+		debug_print("error setting pin!\n");
+		goto fail_data;
+	}
+
+	json_object_object_get_ex(response, "result", &rv_json);
+	if (!rv_json) {
+		debug_print("no result available from %s!", __func__);
+		goto fail_result;
+	}
+
+incorrect_pin:
+	return print_to_ubus(response, ctx, req);
+fail_input:
+	return UBUS_STATUS_INVALID_ARGUMENT;
+fail_data:
+	return UBUS_STATUS_NO_DATA;
+fail_result:
+	json_object_put(response);
+	return UBUS_STATUS_UNKNOWN_ERROR;
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int disable_pin(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__PIN_MAX];
+	char *pin;
+	int rv;
+	struct json_object *response, *rv_json;
+
+	blobmsg_parse(pin_policy, __PIN_MAX, tb, blob_data(msg), blob_len(msg));
+	if (!tb[PIN]) {
+		debug_print("Please enter a pin!\n");
+		goto fail_input;
+	}
+	pin = (char *)blobmsg_data(tb[PIN]);
+	rv = validate_pin_format(pin);
+	if (rv < 0) {
+		debug_print("invalid pin format!\n");
+		goto fail_input;
+	}
+
+	response = mobile_get_pin_status();
+	if (!response) {
+		debug_print("no response from get_pin_status!\n");
+		goto fail_data;
+	}
+
+	json_object_object_get_ex(response, "pin_status", &rv_json);
+	if (!rv_json) {
+		debug_print("no pin_status available in response!\n");
+		goto fail_result;
+	}
+
+	if (!json_object_get_int(rv_json)) {
+		debug_print("already disabled!\n");
+		goto success; //kind of...
+	}
+
+	json_object_put(response);
+	response = mobile_disable_pin(pin);
+	if (!response) {
+		debug_print("error disabling pin!\n");
+		goto fail_data;
+	}
+
+	json_object_object_get_ex(response, "result", &rv_json);
+	if (!rv_json) {
+		debug_print("no result available in response!\n");
+		goto fail_result;
+	}
+
+	if (strncmp(json_object_get_string(rv_json), "failure", strlen("failure")) == 0)
+		debug_print("Incorrect pin!\n");
+
+success:
+	return print_to_ubus(response, ctx, req);
+fail_input:
+	return UBUS_STATUS_INVALID_ARGUMENT;
+fail_data:
+	return UBUS_STATUS_NO_DATA;
+fail_result:
+	json_object_put(response);
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int enable_pin(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__PIN_MAX];
+	char *pin;
+	int rv;
+	struct json_object *response, *rv_json;
+
+	blobmsg_parse(pin_policy, __PIN_MAX, tb, blob_data(msg), blob_len(msg));
+	if (!tb[PIN]) {
+		debug_print("Please enter both a new pin and old pin!\n");
+		goto fail_input;
+	}
+
+	pin = (char *)blobmsg_data(tb[PIN]);
+	rv = validate_pin_format(pin);
+	if (rv < 0) {
+		debug_print("invalid pin format!\n");
+		goto fail_input;
+	}
+
+	response = mobile_get_pin_status();
+	if (!response) {
+		debug_print("no response from get_pin_status!\n");
+		goto fail_data;
+	}
+
+	json_object_object_get_ex(response, "pin_status", &rv_json);
+	if (!rv_json) {
+		debug_print("no pin_status available in response!\n");
+		goto fail_result;
+	}
+	if (!json_object_get_int(rv_json)) {
+		debug_print("already enabled!\n");
+		goto success;
+	}
+
+	json_object_put(response);
+	response = mobile_enable_pin(pin);
+	if (!response) {
+		debug_print("no response from get_pin_status!\n");
+		goto fail_data;
+	}
+
+	json_object_object_get_ex(response, "result", &rv_json);
+	if (!rv_json) {
+		debug_print("no result available in response!\n");
+		goto fail_result;
+	}
+
+	if (strncmp(json_object_get_string(rv_json), "failure", strlen("failure")) == 0)
+		debug_print("Incorrect pin!\n");
+
+success:
+	return print_to_ubus(response, ctx, req);
+fail_input:
+	return UBUS_STATUS_INVALID_ARGUMENT;
+fail_data:
+	return UBUS_STATUS_NO_DATA;
+fail_result:
+	json_object_put(response);
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int verify_pin(struct ubus_context *ctx, struct ubus_object *obj,
+			   struct ubus_request_data *req, const char *method,
+			   struct blob_attr *msg)
+{
+	struct blob_attr *tb[__PIN_MAX];
+	char *pin;
+	int rv;
+	struct json_object *response;
+
+	blobmsg_parse(pin_policy, __PIN_MAX, tb, blob_data(msg), blob_len(msg));
+	if (!tb[PIN]) {
+		debug_print("Please enter a pin\n!");
+		goto fail_input;
+	}
+
+	pin = (char *)blobmsg_data(tb[PIN]);
+	rv = validate_pin_format(pin);
+	if (rv < 0) {
+		debug_print("invalid pin format!\n");
+		goto fail_input;
+	}
+
+	response = mobile_set_pin(pin, pin);
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_input:
+	return UBUS_STATUS_INVALID_ARGUMENT;
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+int remaining_tries(struct ubus_context *ctx, struct ubus_object *obj,
+			   struct ubus_request_data *req, const char *method,
+			   struct blob_attr *msg)
+{
+	struct json_object *response = mobile_get_remaining_tries();
+
+	if (!response)
+		goto fail_unknown;
+
+	return print_to_ubus(response, ctx, req);
+fail_unknown:
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
+struct ubus_method pin_object_methods[] = {
+	UBUS_METHOD("set_pin", set_pin, set_pin_policy),
+	UBUS_METHOD("disable_pin", disable_pin, pin_policy),
+	UBUS_METHOD("enable_pin", enable_pin, pin_policy),
+	UBUS_METHOD("verify_pin", verify_pin, pin_policy),
+	UBUS_METHOD_NOARG("remaining_tries", remaining_tries),
+};
+
+struct ubus_object_type pin_object_type = UBUS_OBJECT_TYPE("dongle", pin_object_methods);
+
+struct ubus_object pin_object = {
+	.name = "dongle.pin",
+	.type = &pin_object_type,
+	.methods = pin_object_methods,
+	.n_methods = ARRAY_SIZE(pin_object_methods),
+};
+
+int expose_pin_object(struct ubus_context *ctx)
+{
+	int rv;
+
+	rv = ubus_add_object(ctx, &pin_object);
+	if (rv) {
+		debug_print("failed to add dongle.pin to ubus!\n");
+		return -1;
+	}
+
+	return 0;
+}
\ No newline at end of file
diff --git a/dongle_pin.h b/dongle_pin.h
new file mode 100644
index 0000000000000000000000000000000000000000..8259165490fd8283fd54a1b6ee7d8338dce32264
--- /dev/null
+++ b/dongle_pin.h
@@ -0,0 +1,6 @@
+#ifndef PIN_H
+#define PIN_H
+#include "common.h"
+
+int expose_pin_object(struct ubus_context *ctx);
+#endif