diff --git a/CHANGES b/CHANGES
index 1119b3f8ad879f509c8dc29b8ed4a0510ae4b038..484237010d0ee63ec6afd6a605f9b335ca900ea7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -109,12 +109,14 @@ MixMonitor
  * Added 'm' option, which stores a copy of the recording as a voicemail in the
    indicated mailboxes.
 
+
 MySQL
 -------------------
  * The connect action in app_mysql now allows you to specify a port number to
    connect to.  This is useful if you run a MySQL server on a non-standard
    port number.
 
+
 OSP Applications
 -------------------
  * Increased the default number of allowed destinations from 5 to 12.
@@ -242,6 +244,9 @@ chan_dahdi
    send connected line information on initial connect; and update, to send
    information on any update during a call.  Default is update.
 
+ * Add options namedcallgroup and namedpickupgroup to support installations
+   where a higher number of groups (>64) is required.
+
 
 chan_motif
 ------------------
@@ -315,15 +320,20 @@ chan_sip
 
  * Add support for WebSocket transport. This can be configured using 'ws' or 'wss'
    as the transport.
+
  * Add options subminexpiry and submaxexpiry to set limits of subscription
    timer independently from registration timer settings. The setting of the
    registration timer limits still is done by options minexpiry, maxexpiry
    and defaultexpiry. For backwards compatibility the setting of minexpiry
    and maxexpiry also is used to configure the subscription timer limits if
    subminexpiry and submaxexpiry are not set in sip.conf.
+
  * Set registration timer limits to default values when reloading sip
    configuration and values are not set by configuration.
 
+ * Add options namedcallgroup and namedpickupgroup to support installations
+   where a higher number of groups (>64) is required.
+
  * When a MESSAGE request is received, the address the request was received from
    is now saved in the SIP_RECVADDR variable.
 
@@ -371,6 +381,12 @@ chan_unistim
    on-screen key
 
 
+chan_mISDN:
+------------------
+ * Add options namedcallgroup and namedpickupgroup to support installations
+   where a higher number of groups (>64) is required.
+
+
 Core
 ------------------
  * The minimum DTMF duration can now be configured in asterisk.conf
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index c0afc576ac30c70c55672a0169af2835ca098cb8..b608383584d1e046faee922354d6563e22b49d52 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -1091,6 +1091,16 @@ struct dahdi_pvt {
 	 * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
 	 */
 	ast_group_t pickupgroup;
+	/*!
+	 * \brief Named call groups this belongs to.
+	 * \note The "namedcallgroup" string read in from chan_dahdi.conf
+	 */
+	struct ast_namedgroups *named_callgroups;
+	/*!
+	 * \brief Named pickup groups this belongs to.
+	 * \note The "namedpickupgroup" string read in from chan_dahdi.conf
+	 */
+	struct ast_namedgroups *named_pickupgroups;
 	/*!
 	 * \brief Channel variable list with associated values to set when a channel is created.
 	 * \note The "setvar" strings read in from chan_dahdi.conf
@@ -5917,6 +5927,10 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
 	if (p->cc_params) {
 		ast_cc_config_params_destroy(p->cc_params);
 	}
+
+	p->named_callgroups = ast_unref_namedgroups(p->named_callgroups);
+	p->named_pickupgroups = ast_unref_namedgroups(p->named_pickupgroups);
+
 	ast_mutex_destroy(&p->lock);
 	dahdi_close_sub(p, SUB_REAL);
 	if (p->owner)
@@ -9904,6 +9918,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 		/* Only FXO signalled stuff can be picked up */
 		ast_channel_callgroup_set(tmp, i->callgroup);
 		ast_channel_pickupgroup_set(tmp, i->pickupgroup);
+		ast_channel_named_callgroups_set(tmp, i->named_callgroups);
+		ast_channel_named_pickupgroups_set(tmp, i->named_pickupgroups);
 	}
 	if (!ast_strlen_zero(i->parkinglot))
 		ast_channel_parkinglot_set(tmp, i->parkinglot);
@@ -13159,6 +13175,10 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 		tmp->group = conf->chan.group;
 		tmp->callgroup = conf->chan.callgroup;
 		tmp->pickupgroup= conf->chan.pickupgroup;
+		ast_unref_namedgroups(tmp->named_callgroups);
+		tmp->named_callgroups = ast_ref_namedgroups(conf->chan.named_callgroups);
+		ast_unref_namedgroups(tmp->named_pickupgroups);
+		tmp->named_pickupgroups = ast_ref_namedgroups(conf->chan.named_pickupgroups);
 		if (conf->chan.vars) {
 			struct ast_variable *v, *tmpvar;
 	                for (v = conf->chan.vars ; v ; v = v->next) {
@@ -17557,6 +17577,10 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 				confp->chan.pickupgroup = 0;
 			else
 				confp->chan.pickupgroup = ast_get_group(v->value);
+		} else if (!strcasecmp(v->name, "namedcallgroup")) {
+			confp->chan.named_callgroups = ast_get_namedgroups(v->value);
+		} else if (!strcasecmp(v->name, "namedpickupgroup")) {
+			confp->chan.named_pickupgroups = ast_get_namedgroups(v->value);
 		} else if (!strcasecmp(v->name, "setvar")) {
 			char *varname = ast_strdupa(v->value), *varval = NULL;
 			struct ast_variable *tmpvar;
@@ -18541,6 +18565,11 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 		}
 		ast_cc_config_params_destroy(conf.chan.cc_params);
 	}
+
+	/* Since named callgroup and named pickup group are ref'd to dahdi_pvt at this point, unref container in confp's pvt. */
+	confp->chan.named_callgroups = ast_unref_namedgroups(confp->chan.named_callgroups);
+	confp->chan.named_pickupgroups = ast_unref_namedgroups(confp->chan.named_pickupgroups);
+
 	return 0;
 }
 
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 82939614a67f0964fd7f6a98a4fd10928dc74aae..ce654ee41e70af68df3f412e24da665a6571f170 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -5904,6 +5904,9 @@ static int read_config(struct chan_list *ch)
 	char buf2[256];
 	ast_group_t pg;
 	ast_group_t cg;
+	struct ast_namedgroups *npg;
+	struct ast_namedgroups *ncg;
+	struct ast_str *tmp_str;
 
 	if (!ch) {
 		ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
@@ -5987,6 +5990,20 @@ static int read_config(struct chan_list *ch)
 	ast_channel_pickupgroup_set(ast, pg);
 	ast_channel_callgroup_set(ast, cg);
 
+	misdn_cfg_get(port, MISDN_CFG_NAMEDPICKUPGROUP, &npg, sizeof(npg));
+	misdn_cfg_get(port, MISDN_CFG_NAMEDCALLGROUP, &ncg, sizeof(ncg));
+
+	tmp_str = ast_str_create(1024);
+	if (tmp_str) {
+		chan_misdn_log(5, port, " --> * NamedCallGrp:%s\n", ast_print_namedgroups(&tmp_str, ncg));
+		ast_str_reset(tmp_str);
+		chan_misdn_log(5, port, " --> * NamedPickupGrp:%s\n", ast_print_namedgroups(&tmp_str, npg));
+		ast_free(tmp_str);
+	}
+
+	ast_channel_named_pickupgroups_set(ast, npg);
+	ast_channel_named_callgroups_set(ast, ncg);
+
 	if (ch->originator == ORG_AST) {
 		char callerid[BUFFERSIZE + 1];
 
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 7afe46f1a939784a40def0a9dc2b554b5bf1a7b1..b002254efe74dd83b327b8c30dcdddcf014d2fd2 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -410,6 +410,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 					<enum name="pickupgroup">
 						<para>The configured Pickupgroup.</para>
 					</enum>
+					<enum name="namedcallgroup">
+						<para>The configured Named Callgroup.</para>
+					</enum>
+					<enum name="namedpickupgroup">
+						<para>The configured Named Pickupgroup.</para>
+					</enum>
 					<enum name="codecs">
 						<para>The configured codecs.</para>
 					</enum>
@@ -1453,6 +1459,7 @@ static char * _sip_show_peers(int fd, int *total, struct mansession *s, const st
 static char *sip_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static char *sip_show_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static void  print_group(int fd, ast_group_t group, int crlf);
+static void  print_named_groups(int fd, struct ast_namedgroups *groups, int crlf);
 static const char *dtmfmode2str(int mode) attribute_const;
 static int str2dtmfmode(const char *str) attribute_unused;
 static const char *insecure2str(int mode) attribute_const;
@@ -4907,6 +4914,9 @@ static void sip_destroy_peer(struct sip_peer *peer)
 		peer->socket.ws_session = NULL;
 	}
 
+	peer->named_callgroups = ast_unref_namedgroups(peer->named_callgroups);
+	peer->named_pickupgroups = ast_unref_namedgroups(peer->named_pickupgroups);
+
 	ast_cc_config_params_destroy(peer->cc_params);
 
 	ast_string_field_free_memory(peer);
@@ -5628,6 +5638,10 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 	ref_proxy(dialog, obproxy_get(dialog, peer));
 	dialog->callgroup = peer->callgroup;
 	dialog->pickupgroup = peer->pickupgroup;
+	ast_unref_namedgroups(dialog->named_callgroups);
+	dialog->named_callgroups = ast_ref_namedgroups(peer->named_callgroups);
+	ast_unref_namedgroups(dialog->named_pickupgroups);
+	dialog->named_pickupgroups = ast_ref_namedgroups(peer->named_pickupgroups);
 	ast_copy_string(dialog->zone, peer->zone, sizeof(dialog->zone));
 	dialog->allowtransfer = peer->allowtransfer;
 	dialog->jointnoncodeccapability = dialog->noncodeccapability;
@@ -6219,6 +6233,9 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
 		p->peerauth = NULL;
 	}
 
+	p->named_callgroups = ast_unref_namedgroups(p->named_callgroups);
+	p->named_pickupgroups = ast_unref_namedgroups(p->named_pickupgroups);
+
 	p->caps = ast_format_cap_destroy(p->caps);
 	p->jointcaps = ast_format_cap_destroy(p->jointcaps);
 	p->peercaps = ast_format_cap_destroy(p->peercaps);
@@ -7570,6 +7587,10 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 
 	ast_channel_callgroup_set(tmp, i->callgroup);
 	ast_channel_pickupgroup_set(tmp, i->pickupgroup);
+
+	ast_channel_named_callgroups_set(tmp, i->named_callgroups);
+	ast_channel_named_pickupgroups_set(tmp, i->named_pickupgroups);
+
 	ast_channel_caller(tmp)->id.name.presentation = i->callingpres;
 	ast_channel_caller(tmp)->id.number.presentation = i->callingpres;
 	if (!ast_strlen_zero(i->parkinglot)) {
@@ -17344,6 +17365,10 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 		p->amaflags = peer->amaflags;
 		p->callgroup = peer->callgroup;
 		p->pickupgroup = peer->pickupgroup;
+		ast_unref_namedgroups(p->named_callgroups);
+		p->named_callgroups = ast_ref_namedgroups(peer->named_callgroups);
+		ast_unref_namedgroups(p->named_pickupgroups);
+		p->named_pickupgroups = ast_ref_namedgroups(peer->named_pickupgroups);
 		ast_format_cap_copy(p->caps, peer->caps);
 		ast_format_cap_copy(p->jointcaps, peer->caps);
 		p->prefs = peer->prefs;
@@ -18347,6 +18372,16 @@ static void print_group(int fd, ast_group_t group, int crlf)
 	ast_cli(fd, crlf ? "%s\r\n" : "%s\n", ast_print_group(buf, sizeof(buf), group) );
 }
 
+/*! \brief Print named call groups and pickup groups */
+static void print_named_groups(int fd, struct ast_namedgroups *group, int crlf)
+{
+	struct ast_str *buf = ast_str_create(1024);
+	if (buf) {
+		ast_cli(fd, crlf ? "%s\r\n" : "%s\n", ast_print_namedgroups(&buf, group) );
+		ast_free(buf);
+	}
+}
+
 /*! \brief mapping between dtmf flags and strings */
 static const struct _map_x_s dtmfstr[] = {
 	{ SIP_DTMF_RFC2833,     "rfc2833" },
@@ -19002,6 +19037,10 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		print_group(fd, peer->callgroup, 0);
 		ast_cli(fd, "  Pickupgroup  : ");
 		print_group(fd, peer->pickupgroup, 0);
+		ast_cli(fd, "  Named Callgr : ");
+		print_named_groups(fd, peer->named_callgroups, 0);
+		ast_cli(fd, "  Nam. Pickupgr: ");
+		print_named_groups(fd, peer->named_pickupgroups, 0);
 		peer_mailboxes_to_str(&mailbox_str, peer);
 		ast_cli(fd, "  MOH Suggest  : %s\n", peer->mohsuggest);
 		ast_cli(fd, "  Mailbox      : %s\n", mailbox_str->str);
@@ -19096,7 +19135,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		peer = sip_unref_peer(peer, "sip_show_peer: sip_unref_peer: done with peer ptr");
 	} else  if (peer && type == 1) { /* manager listing */
 		char buffer[256];
-		struct ast_str *mailbox_str = ast_str_alloca(512);
+		struct ast_str *tmp_str = ast_str_alloca(512);
 		astman_append(s, "Channeltype: SIP\r\n");
 		astman_append(s, "ObjectName: %s\r\n", peer->name);
 		astman_append(s, "ChanObjectType: peer\r\n");
@@ -19118,9 +19157,15 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
 		astman_append(s, "%s\r\n", ast_print_group(buffer, sizeof(buffer), peer->callgroup));
 		astman_append(s, "Pickupgroup: ");
 		astman_append(s, "%s\r\n", ast_print_group(buffer, sizeof(buffer), peer->pickupgroup));
+		astman_append(s, "Named Callgroup: ");
+		astman_append(s, "%s\r\n", ast_print_namedgroups(&tmp_str, peer->named_callgroups));
+		ast_str_reset(tmp_str);
+		astman_append(s, "Named Pickupgroup: ");
+		astman_append(s, "%s\r\n", ast_print_namedgroups(&tmp_str, peer->named_pickupgroups));
+		ast_str_reset(tmp_str);
 		astman_append(s, "MOHSuggest: %s\r\n", peer->mohsuggest);
-		peer_mailboxes_to_str(&mailbox_str, peer);
-		astman_append(s, "VoiceMailbox: %s\r\n", mailbox_str->str);
+		peer_mailboxes_to_str(&tmp_str, peer);
+		astman_append(s, "VoiceMailbox: %s\r\n", tmp_str->str);
 		astman_append(s, "TransferMode: %s\r\n", transfermode2str(peer->allowtransfer));
 		astman_append(s, "LastMsgsSent: %d\r\n", peer->lastmsgssent);
 		astman_append(s, "Maxforwards: %d\r\n", peer->maxforwards);
@@ -19287,6 +19332,10 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 		print_group(a->fd, user->callgroup, 0);
 		ast_cli(a->fd, "  Pickupgroup  : ");
 		print_group(a->fd, user->pickupgroup, 0);
+		ast_cli(a->fd, "  Named Callgr : ");
+		print_named_groups(a->fd, user->named_callgroups, 0);
+		ast_cli(a->fd, "  Nam. Pickupgr: ");
+		print_named_groups(a->fd, user->named_pickupgroups, 0);
 		ast_cli(a->fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), user->cid_name, user->cid_num, "<unspecified>"));
 		ast_cli(a->fd, "  ACL          : %s\n", AST_CLI_YESNO(ast_acl_list_is_empty(user->acl) == 0));
  		ast_cli(a->fd, "  Sess-Timers  : %s\n", stmode2str(user->stimer.st_mode_oper));
@@ -21039,6 +21088,18 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat
 		ast_print_group(buf, len, peer->callgroup);
 	} else  if (!strcasecmp(colname, "pickupgroup")) {
 		ast_print_group(buf, len, peer->pickupgroup);
+	} else  if (!strcasecmp(colname, "namedcallgroup")) {
+		struct ast_str *tmp_str = ast_str_create(1024);
+		if (tmp_str) {
+			ast_copy_string(buf, ast_print_namedgroups(&tmp_str, peer->named_callgroups), len);
+			ast_free(tmp_str);
+		}
+	} else  if (!strcasecmp(colname, "namedpickupgroup")) {
+		struct ast_str *tmp_str = ast_str_create(1024);
+		if (tmp_str) {
+			ast_copy_string(buf, ast_print_namedgroups(&tmp_str, peer->named_pickupgroups), len);
+			ast_free(tmp_str);
+		}
 	} else  if (!strcasecmp(colname, "useragent")) {
 		ast_copy_string(buf, peer->useragent, len);
 	} else  if (!strcasecmp(colname, "mailbox")) {
@@ -29431,6 +29492,10 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 		}
 	}
 
+	/* clear named callgroup and named pickup group container */
+	peer->named_callgroups = ast_unref_namedgroups(peer->named_callgroups);
+	peer->named_pickupgroups = ast_unref_namedgroups(peer->named_pickupgroups);
+
 	for (; v || ((v = alt) && !(alt=NULL)); v = v->next) {
 		if (!devstate_only) {
 			if (handle_common_options(&peerflags[0], &mask[0], v)) {
@@ -29668,6 +29733,10 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 				peer->allowtransfer = ast_true(v->value) ? TRANSFER_OPENFORALL : TRANSFER_CLOSED;
 			} else if (!strcasecmp(v->name, "pickupgroup")) {
 				peer->pickupgroup = ast_get_group(v->value);
+			} else if (!strcasecmp(v->name, "namedcallgroup")) {
+				peer->named_callgroups = ast_get_namedgroups(v->value);
+			} else if (!strcasecmp(v->name, "namedpickupgroup")) {
+				peer->named_pickupgroups = ast_get_namedgroups(v->value);
 			} else if (!strcasecmp(v->name, "allow")) {
 				int error = ast_parse_allow_disallow(&peer->prefs, peer->caps, v->value, TRUE);
 				if (error) {
diff --git a/channels/misdn/chan_misdn_config.h b/channels/misdn/chan_misdn_config.h
index 270b505baa49589038da5e0343394a7b3ac979d9..c4054a87bb3804b0c6ce1747db304fc6322c5c27 100644
--- a/channels/misdn/chan_misdn_config.h
+++ b/channels/misdn/chan_misdn_config.h
@@ -89,6 +89,8 @@ enum misdn_cfg_elements {
 	MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD,              /* int */
 	MISDN_CFG_CALLGROUP,           /* ast_group_t */
 	MISDN_CFG_PICKUPGROUP,         /* ast_group_t */
+	MISDN_CFG_NAMEDCALLGROUP,      /* ast_namedgroups * */
+	MISDN_CFG_NAMEDPICKUPGROUP,    /* ast_namedgroups * */
 	MISDN_CFG_MAX_IN,              /* int */
 	MISDN_CFG_MAX_OUT,              /* int */
 	MISDN_CFG_L1_TIMEOUT,          /* int */
diff --git a/channels/misdn_config.c b/channels/misdn_config.c
index 30e96eca4ba732d004664d74f7b2e1a2a8387aef..32f92c323809a335d7dcd2d93c16df806858dbfd 100644
--- a/channels/misdn_config.c
+++ b/channels/misdn_config.c
@@ -70,7 +70,8 @@ enum misdn_cfg_type {
 	MISDN_CTYPE_BOOL,
 	MISDN_CTYPE_BOOLINT,
 	MISDN_CTYPE_MSNLIST,
-	MISDN_CTYPE_ASTGROUP
+	MISDN_CTYPE_ASTGROUP,
+	MISDN_CTYPE_ASTNAMEDGROUP
 };
 
 struct msn_list {
@@ -83,6 +84,7 @@ union misdn_cfg_pt {
 	int *num;
 	struct msn_list *ml;
 	ast_group_t *grp;
+	struct ast_namedgroups *namgrp;
 	void *any;
 };
 
@@ -330,6 +332,10 @@ static const struct misdn_cfg_spec port_spec[] = {
 		"Callgroup." },
 	{ "pickupgroup", MISDN_CFG_PICKUPGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE,
 		"Pickupgroup." },
+	{ "namedcallgroup", MISDN_CFG_NAMEDCALLGROUP, MISDN_CTYPE_ASTNAMEDGROUP, NO_DEFAULT, NONE,
+		"Named callgroup." },
+	{ "namedpickupgroup", MISDN_CFG_NAMEDPICKUPGROUP, MISDN_CTYPE_ASTNAMEDGROUP, NO_DEFAULT, NONE,
+		"Named pickupgroup." },
 	{ "max_incoming", MISDN_CFG_MAX_IN, MISDN_CTYPE_INT, "-1", NONE,
 		"Defines the maximum amount of incoming calls per port for this group.\n"
 		"\tCalls which exceed the maximum will be marked with the channel variable\n"
@@ -541,10 +547,13 @@ static void _free_port_cfg (void)
 	for (j = 0; free_list[j]; ++j) {
 		for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
 			if (free_list[j][i].any) {
-				if (port_spec[i].type == MISDN_CTYPE_MSNLIST)
+				if (port_spec[i].type == MISDN_CTYPE_MSNLIST) {
 					_free_msn_list(free_list[j][i].ml);
-				else
+				} else if (port_spec[i].type == MISDN_CTYPE_ASTNAMEDGROUP) {
+					ast_unref_namedgroups(free_list[j][i].namgrp);
+				} else {
 					ast_free(free_list[j][i].any);
+				}
 			}
 		}
 	}
@@ -588,6 +597,17 @@ void misdn_cfg_get(int port, enum misdn_cfg_elements elem, void *buf, int bufsiz
 					} else
 						memset(buf, 0, bufsize);
 					break;
+				case MISDN_CTYPE_ASTNAMEDGROUP:
+					if (bufsize >= sizeof(struct ast_namedgroups *)) {
+						if (port_cfg[port][place].namgrp) {
+							*(struct ast_namedgroups **)buf = port_cfg[port][place].namgrp;
+						} else if (port_cfg[0][place].namgrp) {
+							*(struct ast_namedgroups **)buf = port_cfg[0][place].namgrp;
+						} else {
+							*(struct ast_namedgroups **)buf = NULL;
+						}
+					}
+					break;
 				default:
 					if (port_cfg[port][place].any)
 						memcpy(buf, port_cfg[port][place].any, bufsize);
@@ -831,6 +851,25 @@ void misdn_cfg_get_config_string (int port, enum misdn_cfg_elements elem, char*
 			else
 				snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
 			break;
+		case MISDN_CTYPE_ASTNAMEDGROUP:
+			if (port_cfg[port][place].namgrp) {
+				struct ast_str *tmp_str = ast_str_create(1024);
+				if (tmp_str) {
+					snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
+							ast_print_namedgroups(&tmp_str, port_cfg[port][place].namgrp));
+					ast_free(tmp_str);
+				}
+			} else if (port_cfg[0][place].namgrp) {
+				struct ast_str *tmp_str = ast_str_create(1024);
+				if (tmp_str) {
+					snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
+							ast_print_namedgroups(&tmp_str, port_cfg[0][place].namgrp));
+					ast_free(tmp_str);
+				}
+			} else {
+				snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
+			}
+			break;
 		case MISDN_CTYPE_MSNLIST:
 			if (port_cfg[port][place].ml)
 				iter = port_cfg[port][place].ml;
@@ -984,6 +1023,9 @@ static int _parse (union misdn_cfg_pt *dest, const char *value, enum misdn_cfg_t
 		}
 		*(dest->grp) = ast_get_group(value);
 		break;
+	case MISDN_CTYPE_ASTNAMEDGROUP:
+		dest->namgrp = ast_get_namedgroups(value);
+		break;
 	}
 
 	return re;
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index a10d405a972bacb04ee13bab058b58a72c7168ba..a821435e9719c88393f854eaf05772f0421224d6 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -1062,6 +1062,8 @@ struct sip_pvt {
 	uint32_t init_icseq;                    /*!< Initial incoming seqno from first request */
 	ast_group_t callgroup;                  /*!< Call group */
 	ast_group_t pickupgroup;                /*!< Pickup group */
+	struct ast_namedgroups *named_callgroups;   /*!< Named call group */
+	struct ast_namedgroups *named_pickupgroups; /*!< Named pickup group */
 	uint32_t lastinvite;                    /*!< Last seqno of invite */
 	struct ast_flags flags[3];              /*!< SIP_ flags */
 
@@ -1328,6 +1330,8 @@ struct sip_peer {
 	int rtpkeepalive;               /*!<  Send RTP packets for keepalive */
 	ast_group_t callgroup;          /*!<  Call group */
 	ast_group_t pickupgroup;        /*!<  Pickup group */
+	struct ast_namedgroups *named_callgroups;   /*!< Named call group */
+	struct ast_namedgroups *named_pickupgroups; /*!< Named pickup group */
 	struct sip_proxy *outboundproxy;/*!< Outbound proxy for this peer */
 	struct ast_dnsmgr_entry *dnsmgr;/*!<  DNS refresh manager for peer */
 	struct ast_sockaddr addr;        /*!<  IP address of peer */
diff --git a/configs/chan_dahdi.conf.sample b/configs/chan_dahdi.conf.sample
index b747a1e71a8c07b3920b1a298003b21b3ca1a00d..460cd0bdeccbff7fc6d981856ecb8bf21502f212 100644
--- a/configs/chan_dahdi.conf.sample
+++ b/configs/chan_dahdi.conf.sample
@@ -841,6 +841,15 @@ group=1
 ;
 callgroup=1
 pickupgroup=1
+;
+; Named ring groups (a.k.a. named call groups) and named pickup groups.
+; If a phone is ringing and it is a member of a group which is one of your
+; named pickup groups, then you can answer it by picking up and dialing *8#.
+; For simple offices, just make these both the same.
+; The number of named groups is not limited.
+;
+;namedcallgroup=engineering,sales,netgroup,protgroup
+;namedpickupgroup=sales
 
 ; Channel variable to be set for all calls from this channel
 ;setvar=CHANNEL=42
diff --git a/configs/misdn.conf.sample b/configs/misdn.conf.sample
index bd51686e49b895b6f35524dc0c51e6f76021d674..ac54dbc5ad8627d36bdc471ad9ff30fdca5c48ef 100644
--- a/configs/misdn.conf.sample
+++ b/configs/misdn.conf.sample
@@ -390,6 +390,13 @@ nodialtone=no
 ;callgroup=1
 ;pickupgroup=1
 
+; Named pickup groups and named call groups
+;
+; give a name to groups and configure any number of groups
+;
+;namedcallgroup=engineering,sales,netgroup,protgroup
+;namedpickupgroup=sales
+
 ; Set the outgoing caller id to the value.
 ;callerid="name" <number>
 
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index d9ffb85780f9dd5be0061240f4208bb6e2519fa7..81ca998d581bd0f21632e0c052bd5fcd7146b062 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -1432,6 +1432,8 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;
 ;callgroup=1,3-4                 ; We are in caller groups 1,3,4
 ;pickupgroup=1,3-5               ; We can do call pick-p for call group 1,3,4,5
+;namedcallgroup=engineering,sales,netgroup,protgroup ; We are in named call groups engineering,sales,netgroup,protgroup
+;namedpickupgroup=sales          ; We can do call pick-p for named call group sales
 ;defaultip=192.168.0.60          ; IP address to use if peer has not registered
 ;deny=0.0.0.0/0.0.0.0            ; ACL: Control access to this account based on IP address
 ;permit=192.168.0.60/255.255.255.0
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 13d3f1f2945f6f9bd96d6771608cd087bc32b50e..e8785cfe364f72351ed2dfc035e532a3bbbc7c8e 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -973,6 +973,17 @@ enum channelreloadreason {
 	CHANNEL_ACL_RELOAD,
 };
 
+
+/*! \brief Structure to handle ao2-container for named groups */
+struct namedgroup_entry {
+	/*! string representation of group */
+	char *name;
+
+	/*! pre-built hash of groupname string */
+	unsigned int hash;
+};
+
+
 /*!
  * \note None of the datastore API calls lock the ast_channel they are using.
  *       So, the channel should be locked before calling the functions that
@@ -2417,9 +2428,22 @@ static inline enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *c
 
 ast_group_t ast_get_group(const char *s);
 
-/*! \brief print call- and pickup groups into buffer */
+/*! \brief Print call- and pickup groups into buffer */
 char *ast_print_group(char *buf, int buflen, ast_group_t group);
 
+/*! \brief Opaque struct holding a namedgroups set, i.e. a set of group names */
+struct ast_namedgroups;
+
+/*! \brief Create an ast_namedgroups set with group name from comma separated string s */
+struct ast_namedgroups *ast_get_namedgroups(const char *s);
+struct ast_namedgroups *ast_unref_namedgroups(struct ast_namedgroups *groups);
+struct ast_namedgroups *ast_ref_namedgroups(struct ast_namedgroups *groups);
+/*! \brief Return TRUE if group a and b contain at least one common groupname */
+int ast_namedgroups_intersect(struct ast_namedgroups *a, struct ast_namedgroups *b);
+
+/*! \brief Print named call groups and named pickup groups ---*/
+char *ast_print_namedgroups(struct ast_str **buf, struct ast_namedgroups *groups);
+
 /*!
  * \brief Convert enum channelreloadreason to text string for manager event
  * \param reason The reason for reload (manager, cli, start etc)
@@ -3768,6 +3792,8 @@ void ast_channel_redirecting_set(struct ast_channel *chan, struct ast_party_redi
 void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value);
 void ast_channel_whentohangup_set(struct ast_channel *chan, struct timeval *value);
 void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value);
+struct timeval ast_channel_creationtime(struct ast_channel *chan);
+void ast_channel_creationtime_set(struct ast_channel *chan, struct timeval *value);
 
 /* List getters */
 struct ast_hangup_handler_list *ast_channel_hangup_handlers(struct ast_channel *chan);
@@ -3780,6 +3806,10 @@ ast_group_t ast_channel_callgroup(const struct ast_channel *chan);
 void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value);
 ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan);
 void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value);
+struct ast_namedgroups *ast_channel_named_callgroups(const struct ast_channel *chan);
+void ast_channel_named_callgroups_set(struct ast_channel *chan, struct ast_namedgroups *value);
+struct ast_namedgroups *ast_channel_named_pickupgroups(const struct ast_channel *chan);
+void ast_channel_named_pickupgroups_set(struct ast_channel *chan, struct ast_namedgroups *value);
 
 /* Alertpipe accessors--the "internal" functions for channel.c use only */
 typedef enum {
diff --git a/main/channel.c b/main/channel.c
index fdb4f005deeccc4ca3d579c0bd3043eea39b8ea0..4870902847f687b4c585b2afc3400dfe0377e587 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -953,6 +953,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 	struct ast_format_cap *nativeformats;
 	struct ast_sched_context *schedctx;
 	struct ast_timer *timer;
+	struct timeval now;
 
 	/* If shutting down, don't allocate any new channels */
 	if (ast_shutting_down()) {
@@ -1042,6 +1043,9 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 	ast_channel_fin_set(tmp, global_fin);
 	ast_channel_fout_set(tmp, global_fout);
 
+	now = ast_tvnow();
+	ast_channel_creationtime_set(tmp, &now);
+
 	if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
 		ast_channel_uniqueid_build(tmp, "%li.%d", (long) time(NULL),
 			ast_atomic_fetchadd_int(&uniqueint, 1));
@@ -2339,6 +2343,10 @@ static void ast_channel_destructor(void *obj)
 	if (callid) {
 		ast_callid_unref(callid);
 	}
+
+	ast_channel_named_callgroups_set(chan, NULL);
+	ast_channel_named_pickupgroups_set(chan, NULL);
+
 	ast_atomic_fetchadd_int(&chancount, -1);
 }
 
@@ -8074,6 +8082,113 @@ ast_group_t ast_get_group(const char *s)
 	return group;
 }
 
+/*! \brief Comparison function used for named group container */
+static int namedgroup_cmp_cb(void *obj, void *arg, int flags)
+{
+	const struct namedgroup_entry *an = obj;
+	const struct namedgroup_entry *bn = arg;
+	return strcmp(an->name, bn->name) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+/*! \brief Hashing function used for named group container */
+static int namedgroup_hash_cb(const void *obj, const int flags)
+{
+	const struct namedgroup_entry *entry = obj;
+	return entry->hash;
+}
+
+static void namedgroup_dtor(void *obj)
+{
+	ast_free(((struct namedgroup_entry*)obj)->name);
+}
+
+/*! \internal \brief Actually a refcounted ao2_object. An indirect ao2_container to hide the implementation of namedgroups. */
+struct ast_namedgroups {
+	struct ao2_container *container;
+};
+
+static void ast_namedgroups_dtor(void *obj)
+{
+	ao2_cleanup(((struct ast_namedgroups *)obj)->container);
+}
+
+struct ast_namedgroups *ast_get_namedgroups(const char *s)
+{
+	struct ast_namedgroups *namedgroups;
+	char *piece;
+	char *c;
+
+	if (ast_strlen_zero(s)) {
+		return NULL;
+	}
+	c = ast_strdupa(s);
+	if (!c) {
+		return NULL;
+	}
+
+	namedgroups = ao2_alloc_options(sizeof(*namedgroups), ast_namedgroups_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!namedgroups) {
+		return NULL;
+	}
+	namedgroups->container = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 19, namedgroup_hash_cb, namedgroup_cmp_cb);
+	if (!namedgroups->container) {
+		ao2_ref(namedgroups, -1);
+		return NULL;
+	}
+
+	/*! \brief Remove leading and trailing whitespace */
+	c = ast_strip(c);
+
+	while ((piece = strsep(&c, ","))) {
+		struct namedgroup_entry *entry;
+
+		/* remove leading/trailing whitespace */
+		piece = ast_strip(piece);
+		if (strlen(piece) == 0) {
+			ast_log(LOG_ERROR, "Syntax error parsing named group configuration '%s' at '%s'. Ignoring.\n", s, piece);
+			continue;
+		}
+
+		entry = ao2_alloc_options(sizeof(*entry), namedgroup_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+		if (!entry) {
+			ao2_ref(namedgroups, -1);
+			return NULL;
+		}
+		entry->name = ast_strdup(piece);
+		if (!entry->name) {
+			ao2_ref(entry, -1);
+			ao2_ref(namedgroups, -1);
+			return NULL;
+		}
+		entry->hash = ast_str_hash(entry->name);
+		/* every group name may exist only once, delete duplicates */
+		ao2_find(namedgroups->container, entry, OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
+		ao2_link(namedgroups->container, entry);
+		ao2_ref(entry, -1);
+	}
+
+	if (ao2_container_count(namedgroups->container) == 0) {
+		ao2_ref(namedgroups, -1);
+		namedgroups = NULL;
+	}
+
+	return namedgroups;
+}
+
+struct ast_namedgroups *ast_unref_namedgroups(struct ast_namedgroups *groups)
+{
+	ao2_cleanup(groups);
+	return NULL;
+}
+
+struct ast_namedgroups *ast_ref_namedgroups(struct ast_namedgroups *groups)
+{
+	if (groups) {
+		ao2_ref(groups, 1);
+	}
+	return groups;
+}
+
 static int (*ast_moh_start_ptr)(struct ast_channel *, const char *, const char *) = NULL;
 static void (*ast_moh_stop_ptr)(struct ast_channel *) = NULL;
 static void (*ast_moh_cleanup_ptr)(struct ast_channel *) = NULL;
@@ -8304,6 +8419,59 @@ char *ast_print_group(char *buf, int buflen, ast_group_t group)
 	return buf;
 }
 
+/*! \brief Print named call group and named pickup group ---*/
+char *ast_print_namedgroups(struct ast_str **buf, struct ast_namedgroups *group)
+{
+	struct namedgroup_entry *ng;
+	int first = 1;
+	struct ao2_iterator it;
+
+	if (group == NULL) {
+		return ast_str_buffer(*buf);
+	}
+
+	it = ao2_iterator_init(group->container, 0);
+	while ((ng = ao2_iterator_next(&it))) {
+		if (!first) {
+			ast_str_append(buf, 0, ", ");
+		} else {
+			first = 0;
+		}
+		ast_str_append(buf, 0, "%s", ng->name);
+		ao2_ref(ng, -1);
+	}
+	ao2_iterator_destroy(&it);
+
+	return ast_str_buffer(*buf);
+}
+
+static int namedgroup_match(void *obj, void *arg, int flags)
+{
+	void *match;
+
+	match = ao2_find(arg, obj, OBJ_POINTER);
+	ao2_cleanup(match);
+
+	return match ? CMP_MATCH | CMP_STOP : 0;
+}
+
+int ast_namedgroups_intersect(struct ast_namedgroups *a, struct ast_namedgroups *b)
+{
+	/*
+	 * Do a and b intersect? Since b is hash table average time complexity is O(|a|)
+	 */
+	void *match;
+
+	if (!a || !b) {
+		return 0;
+	}
+
+	match = ao2_callback(a->container, 0, namedgroup_match, b->container);
+	ao2_cleanup(match);
+
+	return match != NULL;
+}
+
 void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
 {
 	struct ast_variable *cur;
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index b659fb9b605c4bbf3bbaf65b64d1266eea3dc44c..368940fa132a8feb400016a06df7ecb66e24c5ef 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -136,6 +136,9 @@ struct ast_channel {
 	struct varshead varshead;			/*!< A linked list for channel variables. See \ref AstChanVar */
 	ast_group_t callgroup;				/*!< Call group for call pickups */
 	ast_group_t pickupgroup;			/*!< Pickup group - which calls groups can be picked up? */
+	struct ast_namedgroups *named_callgroups;	/*!< Named call group for call pickups */
+	struct ast_namedgroups *named_pickupgroups;	/*!< Named pickup group - which call groups can be picked up? */
+	struct timeval creationtime;			/*!< The time of channel creation */
 	struct ast_readq_list readq;
 	struct ast_jb jb;				/*!< The jitterbuffer state */
 	struct timeval dtmf_tv;				/*!< The time that an in process digit began, or the last digit ended */
@@ -983,6 +986,14 @@ void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value)
 {
 	chan->varshead = *value;
 }
+struct timeval ast_channel_creationtime(struct ast_channel *chan)
+{
+	return chan->creationtime;
+}
+void ast_channel_creationtime_set(struct ast_channel *chan, struct timeval *value)
+{
+	chan->creationtime = *value;
+}
 
 /* Evil softhangup accessors */
 int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
@@ -1026,6 +1037,24 @@ void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value)
 {
 	chan->pickupgroup = value;
 }
+struct ast_namedgroups *ast_channel_named_callgroups(const struct ast_channel *chan)
+{
+	return chan->named_callgroups;
+}
+void ast_channel_named_callgroups_set(struct ast_channel *chan, struct ast_namedgroups *value)
+{
+	ast_unref_namedgroups(chan->named_callgroups);
+	chan->named_callgroups = ast_ref_namedgroups(value);
+}
+struct ast_namedgroups *ast_channel_named_pickupgroups(const struct ast_channel *chan)
+{
+	return chan->named_pickupgroups;
+}
+void ast_channel_named_pickupgroups_set(struct ast_channel *chan, struct ast_namedgroups *value)
+{
+	ast_unref_namedgroups(chan->named_pickupgroups);
+	chan->named_pickupgroups = ast_ref_namedgroups(value);
+}
 
 /* Alertpipe functions */
 int ast_channel_alert_write(struct ast_channel *chan)
diff --git a/main/features.c b/main/features.c
index 5d0f8ec5dc4a4f739f9e5a6af7121026f61edc05..0794a2f94450cc477a33c54dcd7766ed0a4a0a4f 100644
--- a/main/features.c
+++ b/main/features.c
@@ -7679,10 +7679,19 @@ static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
 	struct ast_channel *chan = data;/*!< Channel wanting to pickup call */
 
 	ast_channel_lock(target);
-	if (chan != target && (ast_channel_pickupgroup(chan) & ast_channel_callgroup(target))
-		&& ast_can_pickup(target)) {
-		/* Return with the channel still locked on purpose */
-		return CMP_MATCH | CMP_STOP;
+
+	/*
+	 * Both, callgroup and namedcallgroup pickup variants are matched independently.
+	 * Checking for named group match is done last since it's a rather expensive operation.
+	 */
+	if (chan != target && ast_can_pickup(target)
+		&& ((ast_channel_pickupgroup(chan) & ast_channel_callgroup(target))
+			|| (ast_namedgroups_intersect(ast_channel_named_pickupgroups(chan), ast_channel_named_callgroups(target))))) {
+		/*
+		 * Return with the channel unlocked on purpose, else we would lock many channels with the chance for deadlock
+		 */
+		ast_channel_unlock(target);
+		return CMP_MATCH;
 	}
 	ast_channel_unlock(target);
 
@@ -7700,11 +7709,36 @@ static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
 int ast_pickup_call(struct ast_channel *chan)
 {
 	struct ast_channel *target;/*!< Potential pickup target */
+	struct ao2_iterator *targets_it;/*!< Potential pickup targets, must find the oldest of them */
+	struct ast_channel *candidate;/*!< Potential new older target */
 	int res = -1;
 	ast_debug(1, "pickup attempt by %s\n", ast_channel_name(chan));
 
-	/* The found channel is already locked. */
-	target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
+	/*
+	 * Transfer all pickup-able channels to another container-iterator.
+	 * Iterate it to find the oldest channel.
+	 */
+	targets_it = (struct ao2_iterator *)ast_channel_callback(find_channel_by_group, NULL, chan, OBJ_MULTIPLE);
+
+	target = NULL;
+	while ((candidate = ao2_iterator_next(targets_it))) {
+		if (!target || ast_tvcmp(ast_channel_creationtime(candidate), ast_channel_creationtime(target)) < 0) {
+			target = candidate;
+		}
+		ast_channel_unref(candidate);
+	}
+	if (target) {
+		/* The found channel must be locked and ref'd. */
+		ast_channel_lock(ast_channel_ref(target));
+		/* Recheck pickup ability */
+		if (!ast_can_pickup(target)) {
+			ast_channel_unlock(target);
+			target = ast_channel_unref(target);/* Bad luck */
+		}
+	}
+
+	ao2_iterator_destroy(targets_it);
+
 	if (target) {
 		ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));