diff --git a/apps/app_dial.c b/apps/app_dial.c
index 1cb91811fed458eaf13026337c55f399e8f43ad4..c8fcf4696ff611e6b838a62f4eb509e4ea2049c4 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -1186,9 +1186,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 	int prestart = num.busy + num.congestion + num.nochan;
 	int orig = *to;
 	struct ast_channel *peer = NULL;
-#ifdef HAVE_EPOLL
-	struct chanlist *epollo;
-#endif
 	struct chanlist *outgoing = AST_LIST_FIRST(out_chans);
 	/* single is set if only one destination is enabled */
 	int single = outgoing && !AST_LIST_NEXT(outgoing, node);
@@ -1227,12 +1224,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 
 	is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL);
 
-#ifdef HAVE_EPOLL
-	AST_LIST_TRAVERSE(out_chans, epollo, node) {
-		ast_poll_channel_add(in, epollo->chan);
-	}
-#endif
-
 	while ((*to = ast_remaining_ms(start, orig)) && !peer) {
 		struct chanlist *o;
 		int pos = 0; /* how many channels do we handle */
@@ -1359,9 +1350,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 			f = ast_read(winner);
 			if (!f) {
 				ast_channel_hangupcause_set(in, ast_channel_hangupcause(c));
-#ifdef HAVE_EPOLL
-				ast_poll_channel_del(in, c);
-#endif
 				ast_channel_publish_dial(in, c, NULL, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(c)));
 				ast_hangup(c);
 				c = o->chan = NULL;
@@ -1786,13 +1774,6 @@ skip_frame:;
 		publish_dial_end_event(in, out_chans, NULL, "NOANSWER");
 	}
 
-#ifdef HAVE_EPOLL
-	AST_LIST_TRAVERSE(out_chans, epollo, node) {
-		if (epollo->chan)
-			ast_poll_channel_del(in, epollo->chan);
-	}
-#endif
-
 	if (is_cc_recall) {
 		ast_cc_completed(in, "Recall completed!");
 	}
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 94686961289991d181e561d5a6f32ba5f5ff94dc..9bba6762d6e795515453c879d179305852b6ff02 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -4794,9 +4794,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 	char membername[80] = "";
 	long starttime = 0;
 	long endtime = 0;
-#ifdef HAVE_EPOLL
-	struct callattempt *epollo;
-#endif
 	char *inchan_name;
 	struct timeval start_time_tv = ast_tvnow();
 	int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
@@ -4806,13 +4803,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 	ast_channel_unlock(qe->chan);
 
 	starttime = (long) time(NULL);
-#ifdef HAVE_EPOLL
-	for (epollo = outgoing; epollo; epollo = epollo->q_next) {
-		if (epollo->chan) {
-			ast_poll_channel_add(in, epollo->chan);
-		}
-	}
-#endif
 
 	while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
 		int numlines, retry, pos = 1;
@@ -5325,14 +5315,6 @@ skip_frame:;
 		publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
 	}
 
-#ifdef HAVE_EPOLL
-	for (epollo = outgoing; epollo; epollo = epollo->q_next) {
-		if (epollo->chan) {
-			ast_poll_channel_del(in, epollo->chan);
-		}
-	}
-#endif
-
 	return peer;
 }
 
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 9a3a967e2e34b961f7197abce3fe68aa005f0663..391e58ccf97543e2d9c5c4b81b5f221f72320af1 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -183,7 +183,8 @@ extern "C" {
 
 #define DATASTORE_INHERIT_FOREVER	INT_MAX
 
-#define AST_MAX_FDS		11
+#define AST_MAX_FDS		11	/*!< original maximum number of file descriptors */
+#define AST_EXTENDED_FDS	12	/*!< the start of extended file descriptor positions */
 /*
  * We have AST_MAX_FDS file descriptors in a channel.
  * Some of them have a fixed use:
@@ -2402,12 +2403,6 @@ void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_par
 /*! Set the file descriptor on the channel */
 void ast_channel_set_fd(struct ast_channel *chan, int which, int fd);
 
-/*! Add a channel to an optimized waitfor */
-void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1);
-
-/*! Delete a channel from an optimized waitfor */
-void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1);
-
 /*! Start a tone going */
 int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol);
 /*! Stop a tone from playing */
@@ -4300,11 +4295,30 @@ void ast_channel_internal_fd_set(struct ast_channel *chan, int which, int value)
 int ast_channel_fd(const struct ast_channel *chan, int which);
 int ast_channel_fd_isset(const struct ast_channel *chan, int which);
 
-/* epoll data internal accessors */
-#ifdef HAVE_EPOLL
-struct ast_epoll_data *ast_channel_internal_epfd_data(const struct ast_channel *chan, int which);
-void ast_channel_internal_epfd_data_set(struct ast_channel *chan, int which , struct ast_epoll_data *value);
-#endif
+/*!
+ * \since 15
+ * \brief Retrieve the number of file decriptor positions present on the channel
+ *
+ * \param chan The channel to get the count of
+ *
+ * \pre chan is locked
+ *
+ * \return The number of file descriptor positions
+ */
+int ast_channel_fd_count(const struct ast_channel *chan);
+
+/*!
+ * \since 15
+ * \brief Add a file descriptor to the channel without a fixed position
+ *
+ * \param chan The channel to add the file descriptor to
+ * \param value The file descriptor
+ *
+ * \pre chan is locked
+ *
+ * \return The position of the file descriptor
+ */
+int ast_channel_fd_add(struct ast_channel *chan, int value);
 
 pthread_t ast_channel_blocker(const struct ast_channel *chan);
 void ast_channel_blocker_set(struct ast_channel *chan, pthread_t value);
diff --git a/main/channel.c b/main/channel.c
index 15c7fa4062c5f6fa14e984608c55febade536979..31f363938f1e1779892575fe739c5835be285dcb 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -78,21 +78,12 @@
 /*** DOCUMENTATION
  ***/
 
-#ifdef HAVE_EPOLL
-#include <sys/epoll.h>
-#endif
-
 #if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED)
 #if defined(HAVE_PRI)
 #include "libpri.h"
 #endif	/* defined(HAVE_PRI) */
 #endif	/* defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) */
 
-struct ast_epoll_data {
-	struct ast_channel *chan;
-	int which;
-};
-
 /* uncomment if you have problems with 'monitoring' synchronized files */
 #if 0
 #define MONITOR_CONSTANT_DELAY
@@ -850,10 +841,6 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 	ast_channel_internal_alertpipe_clear(tmp);
 	ast_channel_internal_fd_clear_all(tmp);
 
-#ifdef HAVE_EPOLL
-	ast_channel_epfd_set(tmp, epoll_create(25));
-#endif
-
 	if (!(schedctx = ast_sched_context_create())) {
 		ast_log(LOG_WARNING, "Channel allocation failed: Unable to create schedule context\n");
 		/* See earlier channel creation abort comment above. */
@@ -1058,9 +1045,6 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const
 	ast_channel_timingfd_set(tmp, -1);
 	ast_channel_internal_alertpipe_clear(tmp);
 	ast_channel_internal_fd_clear_all(tmp);
-#ifdef HAVE_EPOLL
-	ast_channel_epfd_set(tmp, -1);
-#endif
 
 	ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD);
 
@@ -2223,9 +2207,6 @@ void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
 static void ast_channel_destructor(void *obj)
 {
 	struct ast_channel *chan = obj;
-#ifdef HAVE_EPOLL
-	int i;
-#endif
 	struct ast_var_t *vardata;
 	struct ast_frame *f;
 	struct varshead *headp;
@@ -2323,14 +2304,6 @@ static void ast_channel_destructor(void *obj)
 		ast_timer_close(ast_channel_timer(chan));
 		ast_channel_timer_set(chan, NULL);
 	}
-#ifdef HAVE_EPOLL
-	for (i = 0; i < AST_MAX_FDS; i++) {
-		if (ast_channel_internal_epfd_data(chan, i)) {
-			ast_free(ast_channel_internal_epfd_data(chan, i));
-		}
-	}
-	close(ast_channel_epfd(chan));
-#endif
 	while ((f = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list)))
 		ast_frfree(f);
 
@@ -2481,82 +2454,10 @@ struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const
 /*! Set the file descriptor on the channel */
 void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
 {
-#ifdef HAVE_EPOLL
-	struct epoll_event ev;
-	struct ast_epoll_data *aed = NULL;
-
-	if (ast_channel_fd_isset(chan, which)) {
-		epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_DEL, ast_channel_fd(chan, which), &ev);
-		aed = ast_channel_internal_epfd_data(chan, which);
-	}
-
-	/* If this new fd is valid, add it to the epoll */
-	if (fd > -1) {
-		if (!aed && (!(aed = ast_calloc(1, sizeof(*aed)))))
-			return;
-
-		ast_channel_internal_epfd_data_set(chan, which, aed);
-		aed->chan = chan;
-		aed->which = which;
-
-		ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
-		ev.data.ptr = aed;
-		epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_ADD, fd, &ev);
-	} else if (aed) {
-		/* We don't have to keep around this epoll data structure now */
-		ast_free(aed);
-		ast_channel_epfd_data_set(chan, which, NULL);
-	}
-#endif
 	ast_channel_internal_fd_set(chan, which, fd);
 	return;
 }
 
-/*! Add a channel to an optimized waitfor */
-void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1)
-{
-#ifdef HAVE_EPOLL
-	struct epoll_event ev;
-	int i = 0;
-
-	if (ast_channel_epfd(chan0) == -1)
-		return;
-
-	/* Iterate through the file descriptors on chan1, adding them to chan0 */
-	for (i = 0; i < AST_MAX_FDS; i++) {
-		if (!ast_channel_fd_isset(chan1, i)) {
-			continue;
-		}
-		ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
-		ev.data.ptr = ast_channel_internal_epfd_data(chan1, i);
-		epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_ADD, ast_channel_fd(chan1, i), &ev);
-	}
-
-#endif
-	return;
-}
-
-/*! Delete a channel from an optimized waitfor */
-void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1)
-{
-#ifdef HAVE_EPOLL
-	struct epoll_event ev;
-	int i = 0;
-
-	if (ast_channel_epfd(chan0) == -1)
-		return;
-
-	for (i = 0; i < AST_MAX_FDS; i++) {
-		if (!ast_channel_fd_isset(chan1, i)) {
-			continue;
-		}
-		epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_DEL, ast_channel_fd(chan1, i), &ev);
-	}
-
-#endif
-	return;
-}
-
 void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
 {
 	ast_channel_lock(chan);
@@ -3061,20 +2962,15 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
 }
 
 /*! \brief Wait for x amount of time on a file descriptor to have input.  */
-#ifdef HAVE_EPOLL
-static struct ast_channel *ast_waitfor_nandfds_classic(struct ast_channel **c, int n, int *fds, int nfds,
-					int *exception, int *outfd, int *ms)
-#else
 struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds,
 					int *exception, int *outfd, int *ms)
-#endif
 {
 	struct timeval start = { 0 , 0 };
 	struct pollfd *pfds = NULL;
 	int res;
 	long rms;
 	int x, y, max;
-	int sz;
+	int sz = nfds;
 	struct timeval now = { 0, 0 };
 	struct timeval whentohangup = { 0, 0 }, diff;
 	struct ast_channel *winner = NULL;
@@ -3090,14 +2986,6 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 		*exception = 0;
 	}
 
-	if ((sz = n * AST_MAX_FDS + nfds)) {
-		pfds = ast_alloca(sizeof(*pfds) * sz);
-		fdmap = ast_alloca(sizeof(*fdmap) * sz);
-	} else {
-		/* nothing to allocate and no FDs to check */
-		return NULL;
-	}
-
 	for (x = 0; x < n; x++) {
 		ast_channel_lock(c[x]);
 		if (!ast_tvzero(*ast_channel_whentohangup(c[x]))) {
@@ -3114,8 +3002,17 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 			if (ast_tvzero(whentohangup) || ast_tvcmp(diff, whentohangup) < 0)
 				whentohangup = diff;
 		}
+		sz += ast_channel_fd_count(c[x]);
 		ast_channel_unlock(c[x]);
 	}
+
+	if (!sz) {
+		return NULL;
+	}
+
+	pfds = ast_alloca(sizeof(*pfds) * sz);
+	fdmap = ast_alloca(sizeof(*fdmap) * sz);
+
 	/* Wait full interval */
 	rms = *ms;
 	/* INT_MAX, not LONG_MAX, because it matters on 64-bit */
@@ -3135,12 +3032,12 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 	 */
 	max = 0;
 	for (x = 0; x < n; x++) {
-		for (y = 0; y < AST_MAX_FDS; y++) {
+		ast_channel_lock(c[x]);
+		for (y = 0; y < ast_channel_fd_count(c[x]); y++) {
 			fdmap[max].fdno = y;  /* fd y is linked to this pfds */
 			fdmap[max].chan = x;  /* channel x is linked to this pfds */
 			max += ast_add_fd(&pfds[max], ast_channel_fd(c[x], y));
 		}
-		ast_channel_lock(c[x]);
 		CHECK_BLOCKING(c[x]);
 		ast_channel_unlock(c[x]);
 	}
@@ -3234,205 +3131,6 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 	return winner;
 }
 
-#ifdef HAVE_EPOLL
-static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan, int *ms)
-{
-	struct timeval start = { 0 , 0 };
-	int res = 0;
-	struct epoll_event ev[1];
-	long diff, rms = *ms;
-	struct ast_channel *winner = NULL;
-	struct ast_epoll_data *aed = NULL;
-
-	ast_channel_lock(chan);
-	/* Figure out their timeout */
-	if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
-		if ((diff = ast_tvdiff_ms(*ast_channel_whentohangup(chan), ast_tvnow())) < 0) {
-			/* They should already be hungup! */
-			ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_TIMEOUT);
-			ast_channel_unlock(chan);
-			return NULL;
-		}
-		/* If this value is smaller then the current one... make it priority */
-		if (rms > diff) {
-			rms = diff;
-		}
-	}
-
-	ast_channel_unlock(chan);
-
-	/* Time to make this channel block... */
-	CHECK_BLOCKING(chan);
-
-	if (*ms > 0) {
-		start = ast_tvnow();
-	}
-
-	/* We don't have to add any file descriptors... they are already added, we just have to wait! */
-	res = epoll_wait(ast_channel_epfd(chan), ev, 1, rms);
-
-	/* Stop blocking */
-	ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING);
-
-	/* Simulate a timeout if we were interrupted */
-	if (res < 0) {
-		if (errno != EINTR) {
-			*ms = -1;
-		}
-		return NULL;
-	}
-
-	/* If this channel has a timeout see if it expired */
-	if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
-		if (ast_tvdiff_ms(ast_tvnow(), *ast_channel_whentohangup(chan)) >= 0) {
-			ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_TIMEOUT);
-			winner = chan;
-		}
-	}
-
-	/* No fd ready, reset timeout and be done for now */
-	if (!res) {
-		*ms = 0;
-		return winner;
-	}
-
-	/* See what events are pending */
-	aed = ev[0].data.ptr;
-	ast_channel_fdno_set(chan, aed->which);
-	if (ev[0].events & EPOLLPRI) {
-		ast_set_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
-	} else {
-		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
-	}
-
-	if (*ms > 0) {
-		*ms -= ast_tvdiff_ms(ast_tvnow(), start);
-		if (*ms < 0) {
-			*ms = 0;
-		}
-	}
-
-	return chan;
-}
-
-static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, int n, int *ms)
-{
-	struct timeval start = { 0 , 0 };
-	int res = 0, i;
-	struct epoll_event ev[25] = { { 0, } };
-	struct timeval now = { 0, 0 };
-	long whentohangup = 0, diff = 0, rms = *ms;
-	struct ast_channel *winner = NULL;
-
-	for (i = 0; i < n; i++) {
-		ast_channel_lock(c[i]);
-		if (!ast_tvzero(*ast_channel_whentohangup(c[i]))) {
-			if (whentohangup == 0) {
-				now = ast_tvnow();
-			}
-			if ((diff = ast_tvdiff_ms(*ast_channel_whentohangup(c[i]), now)) < 0) {
-				ast_channel_softhangup_internal_flag_add(c[i], AST_SOFTHANGUP_TIMEOUT);
-				ast_channel_unlock(c[i]);
-				return c[i];
-			}
-			if (!whentohangup || whentohangup > diff) {
-				whentohangup = diff;
-			}
-		}
-		ast_channel_unlock(c[i]);
-		CHECK_BLOCKING(c[i]);
-	}
-
-	rms = *ms;
-	if (whentohangup) {
-		rms = whentohangup;
-		if (*ms >= 0 && *ms < rms) {
-			rms = *ms;
-		}
-	}
-
-	if (*ms > 0) {
-		start = ast_tvnow();
-	}
-
-	res = epoll_wait(ast_channel_epfd(c[0]), ev, 25, rms);
-
-	for (i = 0; i < n; i++) {
-		ast_clear_flag(ast_channel_flags(c[i]), AST_FLAG_BLOCKING);
-	}
-
-	if (res < 0) {
-		if (errno != EINTR) {
-			*ms = -1;
-		}
-		return NULL;
-	}
-
-	if (whentohangup) {
-		now = ast_tvnow();
-		for (i = 0; i < n; i++) {
-			if (!ast_tvzero(*ast_channel_whentohangup(c[i])) && ast_tvdiff_ms(now, *ast_channel_whentohangup(c[i])) >= 0) {
-				ast_channel_softhangup_internal_flag_add(c[i], AST_SOFTHANGUP_TIMEOUT);
-				if (!winner) {
-					winner = c[i];
-				}
-			}
-		}
-	}
-
-	if (!res) {
-		*ms = 0;
-		return winner;
-	}
-
-	for (i = 0; i < res; i++) {
-		struct ast_epoll_data *aed = ev[i].data.ptr;
-
-		if (!ev[i].events || !aed) {
-			continue;
-		}
-
-		winner = aed->chan;
-		if (ev[i].events & EPOLLPRI) {
-			ast_set_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION);
-		} else {
-			ast_clear_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION);
-		}
-		ast_channel_fdno_set(winner, aed->which);
-	}
-
-	if (*ms > 0) {
-		*ms -= ast_tvdiff_ms(ast_tvnow(), start);
-		if (*ms < 0) {
-			*ms = 0;
-		}
-	}
-
-	return winner;
-}
-
-struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds,
-					int *exception, int *outfd, int *ms)
-{
-	/* Clear all provided values in one place. */
-	if (outfd) {
-		*outfd = -99999;
-	}
-	if (exception) {
-		*exception = 0;
-	}
-
-	/* If no epoll file descriptor is available resort to classic nandfds */
-	if (!n || nfds || ast_channel_epfd(c[0]) == -1) {
-		return ast_waitfor_nandfds_classic(c, n, fds, nfds, exception, outfd, ms);
-	} else if (!nfds && n == 1) {
-		return ast_waitfor_nandfds_simple(c[0], ms);
-	} else {
-		return ast_waitfor_nandfds_complex(c, n, ms);
-	}
-}
-#endif
-
 struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
 {
 	return ast_waitfor_nandfds(c, n, NULL, 0, NULL, NULL, ms);
@@ -6852,6 +6550,7 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 	int origstate;
 	unsigned int orig_disablestatecache;
 	unsigned int clone_disablestatecache;
+	int generator_fd;
 	int visible_indication;
 	int clone_hold_state;
 	int moh_is_playing;
@@ -7042,8 +6741,13 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 	/* Keep the same parkinglot. */
 	ast_channel_parkinglot_set(original, ast_channel_parkinglot(clonechan));
 
-	/* Copy the FD's other than the generator fd */
-	for (x = 0; x < AST_MAX_FDS; x++) {
+	/* Clear all existing file descriptors but retain the generator */
+	generator_fd = ast_channel_fd(original, AST_GENERATOR_FD);
+	ast_channel_internal_fd_clear_all(original);
+	ast_channel_set_fd(original, AST_GENERATOR_FD, generator_fd);
+
+	/* Copy all file descriptors present on clonechan to original, skipping generator */
+	for (x = 0; x < ast_channel_fd_count(clonechan); x++) {
 		if (x != AST_GENERATOR_FD)
 			ast_channel_set_fd(original, x, ast_channel_fd(clonechan, x));
 	}
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index d7ae8f9c118bf86a645f004b9f6e53a4d08c81b4..b3c0a480538ce66f038d361d4c6b2a66537c3a56 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -48,6 +48,7 @@
 #include "asterisk/stringfields.h"
 #include "asterisk/stream.h"
 #include "asterisk/test.h"
+#include "asterisk/vector.h"
 
 /*!
  * \brief Channel UniqueId structure
@@ -96,9 +97,6 @@ struct ast_channel {
 							 *   in the CHANNEL dialplan function */
 	struct ast_channel_monitor *monitor;		/*!< Channel monitoring */
 	ast_callid callid;			/*!< Bound call identifier pointer */
-#ifdef HAVE_EPOLL
-	struct ast_epoll_data *epfd_data[AST_MAX_FDS];
-#endif
 	struct ao2_container *dialed_causes;		/*!< Contains tech-specific and Asterisk cause data from dialed channels */
 
 	AST_DECLARE_STRING_FIELDS(
@@ -167,7 +165,7 @@ struct ast_channel {
 	unsigned long insmpl;				/*!< Track the read/written samples for monitor use */
 	unsigned long outsmpl;				/*!< Track the read/written samples for monitor use */
 
-	int fds[AST_MAX_FDS];				/*!< File descriptors for channel -- Drivers will poll on
+	AST_VECTOR(, int) fds;				/*!< File descriptors for channel -- Drivers will poll on
 							 *   these file descriptors, so at least one must be non -1.
 							 *   See \arg \ref AstFileDesc */
 	int softhangup;				/*!< Whether or not we have been hung up...  Do not set this value
@@ -197,9 +195,6 @@ struct ast_channel {
 	struct ast_format *rawreadformat;         /*!< Raw read format (before translation) */
 	struct ast_format *rawwriteformat;        /*!< Raw write format (after translation) */
 	unsigned int emulate_dtmf_duration;		/*!< Number of ms left to emulate DTMF for */
-#ifdef HAVE_EPOLL
-	int epfd;
-#endif
 	int visible_indication;                         /*!< Indication currently playing on the channel */
 	int hold_state;							/*!< Current Hold/Unhold state */
 
@@ -597,17 +592,6 @@ void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value)
 	chan->amaflags = value;
 	ast_channel_publish_snapshot(chan);
 }
-
-#ifdef HAVE_EPOLL
-int ast_channel_epfd(const struct ast_channel *chan)
-{
-	return chan->epfd;
-}
-void ast_channel_epfd_set(struct ast_channel *chan, int value)
-{
-	chan->epfd = value;
-}
-#endif
 int ast_channel_fdno(const struct ast_channel *chan)
 {
 	return chan->fdno;
@@ -1432,38 +1416,55 @@ void ast_channel_internal_alertpipe_swap(struct ast_channel *chan1, struct ast_c
 /* file descriptor array accessors */
 void ast_channel_internal_fd_set(struct ast_channel *chan, int which, int value)
 {
-	chan->fds[which] = value;
+	int pos;
+
+	/* This ensures that if the vector has to grow with unused positions they will be
+	 * initialized to -1.
+	 */
+	for (pos = AST_VECTOR_SIZE(&chan->fds); pos < which; pos++) {
+		AST_VECTOR_REPLACE(&chan->fds, pos, -1);
+	}
+
+	AST_VECTOR_REPLACE(&chan->fds, which, value);
 }
 void ast_channel_internal_fd_clear(struct ast_channel *chan, int which)
 {
-	ast_channel_internal_fd_set(chan, which, -1);
+	if (which >= AST_VECTOR_SIZE(&chan->fds)) {
+		return;
+	}
+
+	AST_VECTOR_REPLACE(&chan->fds, which, -1);
 }
 void ast_channel_internal_fd_clear_all(struct ast_channel *chan)
 {
-	int i;
-	for (i = 0; i < AST_MAX_FDS; i++) {
-		ast_channel_internal_fd_clear(chan, i);
-	}
+	AST_VECTOR_RESET(&chan->fds, AST_VECTOR_ELEM_CLEANUP_NOOP);
 }
 int ast_channel_fd(const struct ast_channel *chan, int which)
 {
-	return chan->fds[which];
+	return (which >= AST_VECTOR_SIZE(&chan->fds)) ? -1 : AST_VECTOR_GET(&chan->fds, which);
 }
 int ast_channel_fd_isset(const struct ast_channel *chan, int which)
 {
 	return ast_channel_fd(chan, which) > -1;
 }
 
-#ifdef HAVE_EPOLL
-struct ast_epoll_data *ast_channel_internal_epfd_data(const struct ast_channel *chan, int which)
+int ast_channel_fd_count(const struct ast_channel *chan)
 {
-	return chan->epfd_data[which];
+	return AST_VECTOR_SIZE(&chan->fds);
 }
-void ast_channel_internal_epfd_data_set(struct ast_channel *chan, int which , struct ast_epoll_data *value)
+
+int ast_channel_fd_add(struct ast_channel *chan, int value)
 {
-	chan->epfd_data[which] = value;
+	int pos = AST_EXTENDED_FDS;
+
+	while (ast_channel_fd_isset(chan, pos)) {
+		pos += 1;
+	}
+
+	AST_VECTOR_REPLACE(&chan->fds, pos, value);
+
+	return pos;
 }
-#endif
 
 pthread_t ast_channel_blocker(const struct ast_channel *chan)
 {
@@ -1617,6 +1618,8 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj),
 		tmp->linkedid = tmp->uniqueid;
 	}
 
+	AST_VECTOR_INIT(&tmp->fds, AST_MAX_FDS);
+
 	return tmp;
 }
 
@@ -1693,6 +1696,8 @@ void ast_channel_internal_cleanup(struct ast_channel *chan)
 	chan->topics = NULL;
 
 	ast_channel_internal_set_stream_topology(chan, NULL);
+
+	AST_VECTOR_FREE(&chan->fds);
 }
 
 void ast_channel_internal_finalize(struct ast_channel *chan)
diff --git a/main/dial.c b/main/dial.c
index cc2366ed7aa2cb93825ba1cb72ea0b063b7241f9..d0492dcfdda34a21bc9169394a490528927ed3f0 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -479,9 +479,6 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann
 		ast_hangup(channel->owner);
 		channel->owner = NULL;
 	} else {
-		if (chan) {
-			ast_poll_channel_add(chan, channel->owner);
-		}
 		ast_channel_publish_dial(async ? NULL : chan, channel->owner, channel->device, NULL);
 		res = 1;
 		ast_verb(3, "Called %s\n", numsubst);
@@ -868,8 +865,6 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
 				set_state(dial, AST_DIAL_RESULT_HANGUP);
 				break;
 			}
-			if (chan)
-				ast_poll_channel_del(chan, channel->owner);
 			ast_channel_publish_dial(chan, who, channel->device, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(who)));
 			ast_hangup(who);
 			channel->owner = NULL;
@@ -890,8 +885,6 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
 		AST_LIST_TRAVERSE(&dial->channels, channel, list) {
 			if (!channel->owner || channel->owner == who)
 				continue;
-			if (chan)
-				ast_poll_channel_del(chan, channel->owner);
 			ast_channel_publish_dial(chan, channel->owner, channel->device, "CANCEL");
 			ast_hangup(channel->owner);
 			channel->cause = AST_CAUSE_ANSWERED_ELSEWHERE;
@@ -915,8 +908,6 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann
 		AST_LIST_TRAVERSE(&dial->channels, channel, list) {
 			if (!channel->owner)
 				continue;
-			if (chan)
-				ast_poll_channel_del(chan, channel->owner);
 			ast_channel_publish_dial(chan, channel->owner, channel->device, "CANCEL");
 			ast_hangup(channel->owner);
 			channel->cause = AST_CAUSE_NORMAL_CLEARING;
diff --git a/tests/test_channel.c b/tests/test_channel.c
new file mode 100644
index 0000000000000000000000000000000000000000..854aff782dd0ef7be98eb3ac7ff2a2a425c2993c
--- /dev/null
+++ b/tests/test_channel.c
@@ -0,0 +1,119 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2017, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Channel unit tests
+ *
+ * \author Joshua Colp <jcolp@digium.com>
+ *
+ */
+
+/*** MODULEINFO
+	<depend>TEST_FRAMEWORK</depend>
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "asterisk/channel.h"
+
+AST_TEST_DEFINE(set_fd_grow)
+{
+	struct ast_channel *mock_channel;
+	enum ast_test_result_state res = AST_TEST_PASS;
+	int pos;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "set_fd_grow";
+		info->category = "/main/channel/";
+		info->summary = "channel setting file descriptor with growth test";
+		info->description =
+			"Test that setting a file descriptor on a high position of a channel results in -1 set on any new positions";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
+	ast_test_validate_cleanup(test, mock_channel, res, done);
+
+	ast_channel_set_fd(mock_channel, AST_EXTENDED_FDS + 10, 1);
+	ast_test_validate_cleanup(test, ast_channel_fd_count(mock_channel) == AST_EXTENDED_FDS + 11, res, done);
+
+	for (pos = AST_EXTENDED_FDS; (pos < AST_EXTENDED_FDS + 10); pos++) {
+		ast_test_validate_cleanup(test, ast_channel_fd(mock_channel, pos) == -1, res, done);
+	}
+
+done:
+	ast_hangup(mock_channel);
+
+	return res;
+}
+
+AST_TEST_DEFINE(add_fd)
+{
+	struct ast_channel *mock_channel;
+	enum ast_test_result_state res = AST_TEST_PASS;
+	int pos;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "add_fd";
+		info->category = "/main/channel/";
+		info->summary = "channel adding file descriptor test";
+		info->description =
+			"Test that adding a file descriptor to a channel places it in the expected position";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
+	ast_test_validate_cleanup(test, mock_channel, res, done);
+
+	pos = ast_channel_fd_add(mock_channel, 1);
+	ast_test_validate_cleanup(test, pos == AST_EXTENDED_FDS, res, done);
+
+	ast_channel_set_fd(mock_channel, pos, -1);
+	ast_test_validate_cleanup(test, ast_channel_fd(mock_channel, pos) == -1, res, done);
+
+done:
+	ast_hangup(mock_channel);
+
+	return res;
+}
+
+static int unload_module(void)
+{
+	AST_TEST_UNREGISTER(set_fd_grow);
+	AST_TEST_UNREGISTER(add_fd);
+	return 0;
+}
+
+static int load_module(void)
+{
+	AST_TEST_REGISTER(set_fd_grow);
+	AST_TEST_REGISTER(add_fd);
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel Unit Tests");