Commit message: pcpserver.c: copyIPv6IfDifferent() check for NULL src argument
CVE: CVE-2019-12111
CWE: CWE-476
Vulnerability description: A Denial Of Service vulnerability in MiniUPnP MiniUPnPd through 2.1 exists due to a NULL pointer dereference in copyIPv6IfDifferent in pcpserver.c.

Project: miniupnp
File: pcpserver.c

static void CreatePCPMap(pcp_info_t *pcp_msg_info)
{
	int r;

	if (pcp_msg_info->is_fw)
		r = CreatePCPMap_FW(pcp_msg_info);
	else
		r = CreatePCPMap_NAT(pcp_msg_info);
	pcp_msg_info->result_code = r;
	syslog(r == PCP_SUCCESS ? LOG_INFO : LOG_ERR,
	      "PCP MAP: %s mapping %s %hu->%s:%hu '%s'",
	       r == PCP_SUCCESS ? "added" : "failed to add",
	       (pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP",
	       pcp_msg_info->ext_port,
	       pcp_msg_info->mapped_str,
	       pcp_msg_info->int_port,
	       pcp_msg_info->desc);
}

Project: miniupnp
File: pcpserver.c

static int CreatePCPMap_FW(pcp_info_t *pcp_msg_info)
{
#ifdef ENABLE_UPNPPINHOLE
	int uid;
	int r;
	/* first check if pinhole already exists */
	uid = upnp_find_inboundpinhole(NULL, 0,
					pcp_msg_info->mapped_str,
					pcp_msg_info->int_port,
					pcp_msg_info->protocol,
					NULL, 0, /* desc */
					NULL /* lifetime */);
	if(uid >= 0) {
		/* pinhole already exists, updating */
		syslog(LOG_INFO, "updating pinhole to %s:%hu %s",
		       pcp_msg_info->mapped_str, pcp_msg_info->int_port,
		       (pcp_msg_info->protocol == IPPROTO_TCP)?"TCP":"UDP");
		r = upnp_update_inboundpinhole((unsigned short)uid, pcp_msg_info->lifetime);
		return r >= 0 ? PCP_SUCCESS : PCP_ERR_NO_RESOURCES;
	} else {
		r = upnp_add_inboundpinhole(NULL, 0,
						pcp_msg_info->mapped_str,
						pcp_msg_info->int_port,
						pcp_msg_info->protocol,
						pcp_msg_info->desc,
						pcp_msg_info->lifetime,
						&uid);
		if (r < 0)
			return PCP_ERR_NO_RESOURCES;
		pcp_msg_info->ext_port = pcp_msg_info->int_port;
		return PCP_SUCCESS;
	}
#else
	UNUSED(pcp_msg_info);
	return PCP_ERR_NO_RESOURCES;
#endif /* ENABLE_UPNPPINHOLE */
}

Project: miniupnp
File: pcpserver.c

static int CreatePCPMap_NAT(pcp_info_t *pcp_msg_info)
{
	int r = 0;
	char iaddr_old[INET6_ADDRSTRLEN];
	uint16_t iport_old, eport_first = 0;
	int any_eport_allowed = 0;
	unsigned int timestamp = upnp_time() + pcp_msg_info->lifetime;

	if (pcp_msg_info->ext_port == 0) {
		pcp_msg_info->ext_port = pcp_msg_info->int_port;
	}

	/* TODO: Support non-TCP/UDP */
	if (pcp_msg_info->ext_port == 0) {
		return PCP_ERR_MALFORMED_REQUEST;
	}

	do {
		if (eport_first == 0) { /* first time in loop */
			eport_first = pcp_msg_info->ext_port;
		} else if (pcp_msg_info->ext_port == eport_first) { /* no eport available */
                        /* all eports rejected by permissions? */
			if (any_eport_allowed == 0)
				return PCP_ERR_NOT_AUTHORIZED;
			/* at least one eport allowed (but none available) */
			return PCP_ERR_NO_RESOURCES;
		}
		if ((IN6_IS_ADDR_V4MAPPED(pcp_msg_info->mapped_ip) &&
		     (!check_upnp_rule_against_permissions(upnppermlist,
							   num_upnpperm, pcp_msg_info->ext_port,
							   ((struct in_addr*)pcp_msg_info->mapped_ip->s6_addr)[3],
							   pcp_msg_info->int_port)))) {
			if (pcp_msg_info->pfailure_present) {
				return PCP_ERR_CANNOT_PROVIDE_EXTERNAL;
			}
			pcp_msg_info->ext_port++;
			if (pcp_msg_info->ext_port == 0) { /* skip port zero */
				pcp_msg_info->ext_port++;
			}
			continue;
		}
		any_eport_allowed = 1;
#ifdef CHECK_PORTINUSE
		if (port_in_use(ext_if_name, pcp_msg_info->ext_port, pcp_msg_info->protocol,
				pcp_msg_info->mapped_str, pcp_msg_info->int_port) > 0) {
			syslog(LOG_INFO, "port %hu protocol %s already in use",
			       pcp_msg_info->ext_port,
			       (pcp_msg_info->protocol==IPPROTO_TCP)?"tcp":"udp");
			pcp_msg_info->ext_port++;
			if (pcp_msg_info->ext_port == 0) { /* skip port zero */
				pcp_msg_info->ext_port++;
			}
			continue;
		}
#endif
		r = get_redirect_rule(ext_if_name,
				      pcp_msg_info->ext_port,
				      pcp_msg_info->protocol,
				      iaddr_old, sizeof(iaddr_old),
				      &iport_old, 0, 0, 0, 0,
				      NULL/*&timestamp*/, 0, 0);

		if(r==0) {
			if((strcmp(pcp_msg_info->mapped_str, iaddr_old)!=0)
			   || (pcp_msg_info->int_port != iport_old)) {
				/* redirection already existing */
				if (pcp_msg_info->pfailure_present) {
					return PCP_ERR_CANNOT_PROVIDE_EXTERNAL;
				}
			} else {
				syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing",
				       pcp_msg_info->ext_port, (pcp_msg_info->protocol==IPPROTO_TCP)?"tcp":"udp",
				       iaddr_old, iport_old);
				/* remove and then add again */
				if (_upnp_delete_redir(pcp_msg_info->ext_port,
						       pcp_msg_info->protocol)==0) {
					break;
				} else if (pcp_msg_info->pfailure_present) {
					return PCP_ERR_CANNOT_PROVIDE_EXTERNAL;
				}
			}
			pcp_msg_info->ext_port++;
			if (pcp_msg_info->ext_port == 0) { /* skip port zero */
				pcp_msg_info->ext_port++;
			}
		}
	} while (r==0);

	r = upnp_redirect_internal(NULL,
				   pcp_msg_info->ext_port,
				   pcp_msg_info->mapped_str,
				   pcp_msg_info->int_port,
				   pcp_msg_info->protocol,
				   pcp_msg_info->desc,
				   timestamp);
	if (r < 0)
		return PCP_ERR_NO_RESOURCES;
	return PCP_SUCCESS;
}

Project: miniupnp
File: pcpserver.c

static void CreatePCPPeer(pcp_info_t *pcp_msg_info)
{
	char peerip_s[INET6_ADDRSTRLEN];
	int r = -1;

	if (!inet_n46top(pcp_msg_info->peer_ip, peerip_s, sizeof(peerip_s))) {
		syslog(LOG_ERR, "inet_n46top(peer_ip): %m");
		return;
	}

	if (pcp_msg_info->is_fw) {
#if 0
		/* Someday, something like this is available.. and we're ready! */
#ifdef ENABLE_UPNPPINHOLE
		pcp_msg_info->ext_port = pcp_msg_info->int_port;
		r = upnp_add_outbound_pinhole(peerip_s,
					      pcp_msg_info->peer_port,
					      pcp_msg_info->mapped_str,
					      pcp_msg_info->int_port,
					      pcp_msg_info->protocol,
					      pcp_msg_info->desc,
					      pcp_msg_info->lifetime, NULL);
#endif /* ENABLE_UPNPPINHOLE */
#else
		r = PCP_ERR_UNSUPP_OPCODE;
#endif /* 0 */
	} else {
		r = CreatePCPPeer_NAT(pcp_msg_info);
	}
	/* TODO: add upnp function for PI */
	pcp_msg_info->result_code = r;
	syslog(r == PCP_SUCCESS ? LOG_INFO : LOG_ERR,
	       "PCP PEER: %s peer mapping %s %s:%hu(%hu)->%s:%hu '%s'",
	       r == PCP_SUCCESS ? "added" : "failed to add",
	       (pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP",
	       pcp_msg_info->mapped_str,
	       pcp_msg_info->int_port,
	       pcp_msg_info->ext_port,
	       peerip_s,
	       pcp_msg_info->peer_port,
	       pcp_msg_info->desc);
}

Project: miniupnp
File: pcpserver.c

static void DeletePCPMap(pcp_info_t *pcp_msg_info)
{
	uint16_t iport = pcp_msg_info->int_port;  /* private port */
	uint8_t  proto = pcp_msg_info->protocol;
	int r=-1;
	/* remove the mapping */
	/* remove all the mappings for this client */
	int index;
	unsigned short eport2, iport2;
	char iaddr2[INET6_ADDRSTRLEN];
	int proto2;
	char desc[64];
	unsigned int timestamp;
#ifdef ENABLE_UPNPPINHOLE
	int uid = -1;
#endif /* ENABLE_UPNPPINHOLE */

	/* iterate through all rules and delete the requested ones */
	for (index = 0 ;
	     (!pcp_msg_info->is_fw &&
	      get_redirect_rule_by_index(index, 0,
					 &eport2, iaddr2, sizeof(iaddr2),
					 &iport2, &proto2,
					 desc, sizeof(desc),
					 0, 0, &timestamp, 0, 0) >= 0)
#ifdef ENABLE_UPNPPINHOLE
	       ||
	     (pcp_msg_info->is_fw &&
	      (uid=upnp_get_pinhole_uid_by_index(index))>=0 &&
	      upnp_get_pinhole_info((unsigned short)uid,
				    NULL, 0, NULL,
				    iaddr2, sizeof(iaddr2), &iport2,
				    &proto2, desc, sizeof(desc),
				    &timestamp, NULL) >= 0)
#endif /* ENABLE_UPNPPINHOLE */
		     ;
	     index++)
		if(0 == strcmp(iaddr2, pcp_msg_info->mapped_str)
		   && (proto2==proto)
		   && ((iport2==iport) || (iport==0))) {
			if(0 != strcmp(desc, pcp_msg_info->desc)) {
				/* nonce does not match */
				pcp_msg_info->result_code = PCP_ERR_NOT_AUTHORIZED;
				syslog(LOG_ERR, "Unauthorized to remove PCP mapping internal port %hu, protocol %s",
				       iport, (pcp_msg_info->protocol == IPPROTO_TCP)?"TCP":"UDP");
				return;
			} else if (!pcp_msg_info->is_fw) {
				r = _upnp_delete_redir(eport2, proto2);
			} else {
#ifdef ENABLE_UPNPPINHOLE
				r = upnp_delete_inboundpinhole(uid);
#endif /* ENABLE_UPNPPINHOLE */
			}
			break;
		}
	if (r >= 0) {
		syslog(LOG_INFO, "PCP: %s port %hu mapping removed",
		       proto2==IPPROTO_TCP?"TCP":"UDP", eport2);
	} else {
		syslog(LOG_ERR, "Failed to remove PCP mapping internal port %hu, protocol %s",
		       iport, (pcp_msg_info->protocol == IPPROTO_TCP)?"TCP":"UDP");
		pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES;
	}
}

Project: miniupnp
File: pcpserver.c

static void DeletePCPPeer(pcp_info_t *pcp_msg_info)
{
	uint16_t iport = pcp_msg_info->int_port;  /* private port */
	uint16_t rport = pcp_msg_info->peer_port;  /* private port */
	uint8_t  proto = pcp_msg_info->protocol;
	char rhost[INET6_ADDRSTRLEN];
	int r = -1;

	/* remove requested mappings for this client */
	int index = 0;
	unsigned short eport2, iport2, rport2;
	char iaddr2[INET6_ADDRSTRLEN], rhost2[INET6_ADDRSTRLEN];
	int proto2;
	char desc[64];
	unsigned int timestamp;
#if 0
	int uid;
#endif /* 0 */

	if (pcp_msg_info->is_fw) {
		pcp_msg_info->result_code = PCP_ERR_UNSUPP_OPCODE;
		return;
	}

	inet_n46top((struct in6_addr*)pcp_msg_info->peer_ip, rhost, sizeof(rhost));

	for (index = 0 ;
	     (!pcp_msg_info->is_fw &&
	      get_peer_rule_by_index(index, 0,
				     &eport2, iaddr2, sizeof(iaddr2),
				     &iport2, &proto2,
				     desc, sizeof(desc),
				     rhost2, sizeof(rhost2), &rport2,
				     &timestamp, 0, 0) >= 0)
#if 0
		     /* Some day if outbound pinholes are supported.. */
		     ||
		     (pcp_msg_info->is_fw &&
		      (uid=upnp_get_pinhole_uid_by_index(index))>=0 &&
		      upnp_get_pinhole_info((unsigned short)uid,
					    rhost2, sizeof(rhost2), &rport2,
					    iaddr2, sizeof(iaddr2), &iport2,
					    &proto2, desc, sizeof(desc),
					    &timestamp, NULL) >= 0)
#endif /* 0 */
		     ;
	     index++)
		if((0 == strcmp(iaddr2, pcp_msg_info->mapped_str))
		   && (0 == strcmp(rhost2, rhost))
		   && (proto2==proto)
		   && 0 == strcmp(desc, pcp_msg_info->desc)
		   && (iport2==iport) && (rport2==rport)) {
			if (!pcp_msg_info->is_fw)
				r = _upnp_delete_redir(eport2, proto2);
#if 0
			else
				r = upnp_delete_outboundpinhole(uid);
#endif /* 0 */
			if(r<0) {
				syslog(LOG_ERR, "PCP PEER: failed to remove peer mapping");
			} else {
				syslog(LOG_INFO, "PCP PEER: %s port %hu peer mapping removed",
				       proto2==IPPROTO_TCP?"TCP":"UDP", eport2);
			}
			return;
		}
	if (r==-1) {
		syslog(LOG_ERR, "PCP PEER: Failed to find PCP mapping internal port %hu, protocol %s",
		       iport, (pcp_msg_info->protocol == IPPROTO_TCP)?"TCP":"UDP");
		pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES;
	}
}

Project: miniupnp
File: pcpserver.c

static void FillSA(struct sockaddr *sa, const struct in6_addr *in6,
		uint16_t port)
{
	if (IN6_IS_ADDR_V4MAPPED(in6)) {
		struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
		sa4->sin_family = AF_INET;
		sa4->sin_addr.s_addr = ((uint32_t*)(in6)->s6_addr)[3];
		sa4->sin_port = htons(port);
	} else {
		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
		sa6->sin6_family = AF_INET6;
		sa6->sin6_addr = *in6;
		sa6->sin6_port = htons(port);
	}
}

Project: miniupnp
File: pcpserver.c

int OpenAndConfPCPv6Socket(void)
{
	int s;
	int i = 1;
	struct sockaddr_in6 addr;
	s = socket(PF_INET6, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
	if(s < 0) {
		syslog(LOG_ERR, "%s: socket(): %m", "OpenAndConfPCPv6Socket");
		return -1;
	}
	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) {
		syslog(LOG_WARNING, "%s: setsockopt(SO_REUSEADDR): %m",
		       "OpenAndConfPCPv6Socket");
	}
#ifdef IPV6_V6ONLY
	/* force IPV6 only for IPV6 socket.
	 * see http://www.ietf.org/rfc/rfc3493.txt section 5.3 */
	if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i)) < 0) {
		syslog(LOG_WARNING, "%s: setsockopt(IPV6_V6ONLY): %m",
		       "OpenAndConfPCPv6Socket");
	}
#endif
#ifdef IPV6_RECVPKTINFO
	/* see RFC3542 */
	if(setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i, sizeof(i)) < 0) {
		syslog(LOG_WARNING, "%s: setsockopt(IPV6_RECVPKTINFO): %m",
		       "OpenAndConfPCPv6Socket");
	}
#endif
	if(!set_non_blocking(s)) {
		syslog(LOG_WARNING, "%s: set_non_blocking(): %m",
		       "OpenAndConfPCPv6Socket");
	}
	memset(&addr, 0, sizeof(addr));
	addr.sin6_family = AF_INET6;
	addr.sin6_port = htons(NATPMP_PORT);
	addr.sin6_addr = ipv6_bind_addr;
	if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		syslog(LOG_ERR, "%s: bind(): %m", "OpenAndConfPCPv6Socket");
		close(s);
		return -1;
	}
	return s;
}

Project: miniupnp

void PCPPublicAddressChanged(int * sockets, int n_sockets, int socket6)
#else /* IPv4 only */
void PCPPublicAddressChanged(int * sockets, int n_sockets)
#endif
{
	/* according to RFC 6887  8.5 :
	 *   if the external IP address(es) of the NAT (controlled by
	 *   the PCP server) changes, the Epoch time MUST be reset. */
	epoch_origin = upnp_time();
#ifdef ENABLE_IPV6
	PCPSendUnsolicitedAnnounce(sockets, n_sockets, socket6);
#else /* IPv4 Only */
	PCPSendUnsolicitedAnnounce(sockets, n_sockets);
#endif
}

Project: miniupnp

void PCPSendUnsolicitedAnnounce(int * sockets, int n_sockets, int socket6)
#else /* IPv4 only */
void PCPSendUnsolicitedAnnounce(int * sockets, int n_sockets)
#endif
{
	int i;
	unsigned char buff[PCP_MIN_LEN];
	pcp_info_t info;
	ssize_t len;
	struct sockaddr_in addr;
#ifdef ENABLE_IPV6
	struct sockaddr_in6 addr6;
#endif /* ENABLE_IPV6 */
	/* this is an Unsolicited ANNOUNCE response */

	info.version = this_server_info.server_version;
	info.opcode = PCP_OPCODE_ANNOUNCE;
	info.result_code = PCP_SUCCESS;
	info.lifetime = 0;
	createPCPResponse(buff, &info);
	/* Multicast PCP restart announcements are sent to
	 * 224.0.0.1:5350 and/or [ff02::1]:5350 */
	memset(&addr, 0, sizeof(struct sockaddr_in));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("224.0.0.1");
	addr.sin_port = htons(5350);
	for(i = 0; i < n_sockets; i++) {
		len = sendto_or_schedule(sockets[i], buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
		if( len < 0 ) {
			syslog(LOG_ERR, "PCPSendUnsolicitedAnnounce() sendto(): %m");
		}
	}
#ifdef ENABLE_IPV6
	memset(&addr6, 0, sizeof(struct sockaddr_in6));
	addr6.sin6_family = AF_INET6;
	inet_pton(AF_INET6, "FF02::1", &(addr6.sin6_addr));
	addr6.sin6_port = htons(5350);
	len = sendto_or_schedule(socket6, buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6));
	if( len < 0 ) {
		syslog(LOG_ERR, "PCPSendUnsolicitedAnnounce() IPv6 sendto(): %m");
	}
#endif /* ENABLE_IPV6 */
}

Project: miniupnp
File: pcpserver.c

int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len,
                             const struct sockaddr *senderaddr,
                             const struct sockaddr_in6 *receiveraddr)
{
	pcp_info_t pcp_msg_info;
	struct lan_addr_s * lan_addr;
	char addr_str[64];

	memset(&pcp_msg_info, 0, sizeof(pcp_info_t));

	if(senderaddr->sa_family == AF_INET) {
		const struct sockaddr_in * senderaddr_v4 =
			(const struct sockaddr_in *)senderaddr;
		pcp_msg_info.sender_ip.s6_addr[11] = 0xff;
		pcp_msg_info.sender_ip.s6_addr[10] = 0xff;
		memcpy(pcp_msg_info.sender_ip.s6_addr+12,
		       &senderaddr_v4->sin_addr, 4);
	} else if(senderaddr->sa_family == AF_INET6) {
		const struct sockaddr_in6 * senderaddr_v6 =
			(const struct sockaddr_in6 *)senderaddr;
		pcp_msg_info.sender_ip = senderaddr_v6->sin6_addr;
	} else {
		syslog(LOG_WARNING, "unknown PCP packet sender address family %d",
		       senderaddr->sa_family);
		return 0;
	}

	if(sockaddr_to_string(senderaddr, addr_str, sizeof(addr_str)))
		syslog(LOG_DEBUG, "PCP request received from %s %dbytes",
		       addr_str, len);

	if(buff[1] & 128) {
		/* discarding PCP responses silently */
		return 0;
	}

	/* If we're in allow third party-mode, we probably don't care
	 * about locality either. Let's hope firewall is ok. */
	if (!GETFLAG(PCP_ALLOWTHIRDPARTYMASK)) {
		lan_addr = get_lan_for_peer(senderaddr);
		if(lan_addr == NULL) {
			syslog(LOG_WARNING, "PCP packet sender %s not from a LAN, ignoring",
			       addr_str);
			return 0;
		}
	}

	if (processPCPRequest(buff, len, &pcp_msg_info) ) {

		createPCPResponse(buff, &pcp_msg_info);

		if(len < PCP_MIN_LEN)
			len = PCP_MIN_LEN;
		else
			len = (len + 3) & ~3;	/* round up resp. length to multiple of 4 */
		len = sendto_or_schedule2(s, buff, len, 0, senderaddr,
		           (senderaddr->sa_family == AF_INET) ?
		                  sizeof(struct sockaddr_in) :
		                  sizeof(struct sockaddr_in6),
		           receiveraddr);
		if( len < 0 ) {
			syslog(LOG_ERR, "sendto(pcpserver): %m");
		}
	}

	return 0;
}

Project: miniupnp
File: pcpserver.c

static int ValidatePCPMsg(pcp_info_t *pcp_msg_info)
{
	if (pcp_msg_info->result_code) {
		return 0;
	}

	/* RFC 6887, section 8.2: MUST return address mismatch if NAT
	 * in middle. */
	if (memcmp(pcp_msg_info->int_ip,
		   &pcp_msg_info->sender_ip,
		   sizeof(pcp_msg_info->sender_ip)) != 0) {
		pcp_msg_info->result_code = PCP_ERR_ADDRESS_MISMATCH;
		return 0;
	}

	if (pcp_msg_info->thirdp_ip) {
		if (!GETFLAG(PCP_ALLOWTHIRDPARTYMASK)) {
			pcp_msg_info->result_code = PCP_ERR_UNSUPP_OPTION;
			return 0;
		}

		/* RFC687, section 13.1 - if sender ip == THIRD_PARTY,
		 * it's an error. */
		if (memcmp(pcp_msg_info->thirdp_ip,
			   &pcp_msg_info->sender_ip,
			   sizeof(pcp_msg_info->sender_ip)) == 0) {
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
			return 0;
		}
	}

	/* Produce mapped_str for future use. */
	if (!inet_n46top(pcp_msg_info->mapped_ip, pcp_msg_info->mapped_str,
		         sizeof(pcp_msg_info->mapped_str))) {
		syslog(LOG_ERR, "inet_ntop(pcpserver): %m");
		return 0;
	}

	/* protocol zero means 'all protocols' : internal port MUST be zero */
	if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port != 0) {
		syslog(LOG_ERR, "PCP %s: Protocol was ZERO, but internal port "
		       "has non-ZERO value.", getPCPOpCodeStr(pcp_msg_info->opcode));
		pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
		return 0;
	}

	if (pcp_msg_info->pfailure_present) {
		if ( (IN6_IS_ADDR_UNSPECIFIED(pcp_msg_info->ext_ip) ||
		      ((IN6_IS_ADDR_V4MAPPED(pcp_msg_info->ext_ip)) &&
		       (((uint32_t*)pcp_msg_info->ext_ip->s6_addr)[3] == 0))) &&
		     (pcp_msg_info->ext_port == 0)
		   )
		{
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
			return 0;
		}
	}

	if (CheckExternalAddress(pcp_msg_info)) {
		return 0;
	}

	/* Fill in the desc that describes uniquely what flow we're
	 * dealing with (same code used in both create + delete of
	 * MAP/PEER) */
	switch (pcp_msg_info->opcode) {
	case PCP_OPCODE_MAP:
	case PCP_OPCODE_PEER:
		snprintf(pcp_msg_info->desc, sizeof(pcp_msg_info->desc),
			 "PCP %s %08x%08x%08x",
			 getPCPOpCodeStr(pcp_msg_info->opcode),
			 pcp_msg_info->nonce[0],
			 pcp_msg_info->nonce[1], pcp_msg_info->nonce[2]);
		break;
	}
	return 1;
}

Project: miniupnp
File: pcpserver.c

static const char * getPCPOpCodeStr(uint8_t opcode)
{
	switch(opcode) {
	case PCP_OPCODE_ANNOUNCE:
		return "ANNOUNCE";
	case PCP_OPCODE_MAP:
		return "MAP";
	case PCP_OPCODE_PEER:
		return "PEER";
#ifdef  PCP_SADSCP
	case PCP_OPCODE_SADSCP:
		return "SADSCP";
#endif	/* PCP_SADSCP */
	default:
		return "UNKNOWN";
	}
}

Project: miniupnp

int get_dscp_value(pcp_info_t *pcp_msg_info) {

	unsigned int ind;

	for (ind = 0; ind < num_dscp_values; ind++) {

		if ((dscp_values_list[ind].app_name) &&
		    (!strcmp(dscp_values_list[ind].app_name,
			     pcp_msg_info->app_name)) &&
		    (pcp_msg_info->delay_tolerance == dscp_values_list[ind].delay) &&
		    (pcp_msg_info->loss_tolerance == dscp_values_list[ind].loss) &&
		    (pcp_msg_info->jitter_tolerance == dscp_values_list[ind].jitter)
		   )
		{
			pcp_msg_info->sadscp_dscp = dscp_values_list[ind].dscp_value;
			pcp_msg_info->matched_name = 1;
			return 0;
		} else
		  if ((pcp_msg_info->app_name_len==0) &&
		      (dscp_values_list[ind].app_name_len==0) &&
		      (pcp_msg_info->delay_tolerance == dscp_values_list[ind].delay) &&
		      (pcp_msg_info->loss_tolerance == dscp_values_list[ind].loss) &&
		      (pcp_msg_info->jitter_tolerance == dscp_values_list[ind].jitter)
		     )
		{
			pcp_msg_info->sadscp_dscp = dscp_values_list[ind].dscp_value;
			pcp_msg_info->matched_name = 0;
			return 0;
		} else
		  if ((dscp_values_list[ind].app_name_len==0) &&
		      (pcp_msg_info->delay_tolerance == dscp_values_list[ind].delay) &&
		      (pcp_msg_info->loss_tolerance == dscp_values_list[ind].loss) &&
		      (pcp_msg_info->jitter_tolerance == dscp_values_list[ind].jitter)
		     )
		{
			pcp_msg_info->sadscp_dscp = dscp_values_list[ind].dscp_value;
			pcp_msg_info->matched_name = 0;
			return 0;
		}
	}
	pcp_msg_info->sadscp_dscp = 0;
	pcp_msg_info->matched_name = 0;
	return 0;
}

Project: miniupnp
File: pcpserver.c

static const char* inet_n46top(const struct in6_addr* in,
			       char* buf, size_t buf_len)
{
	if (IN6_IS_ADDR_V4MAPPED(in)) {
		return inet_ntop(AF_INET, ((uint32_t*)(in->s6_addr))+3, buf, buf_len);
	} else {
		return inet_ntop(AF_INET6, in, buf, buf_len);
	}
}

Project: miniupnp
File: pcpserver.c

static int parseCommonRequestHeader(const uint8_t *common_req, pcp_info_t *pcp_msg_info)
{
	pcp_msg_info->version = common_req[0] ;
	pcp_msg_info->opcode = common_req[1] & 0x7f;
	pcp_msg_info->lifetime = READNU32(common_req + 4);
	pcp_msg_info->int_ip = (struct in6_addr *)(common_req + 8);
	pcp_msg_info->mapped_ip = (struct in6_addr *)(common_req + 8);


	if ( (pcp_msg_info->version > this_server_info.server_version) ) {
		pcp_msg_info->result_code = PCP_ERR_UNSUPP_VERSION;
		return 1;
	}

	if (pcp_msg_info->lifetime > max_lifetime ) {
		pcp_msg_info->lifetime = max_lifetime;
	}

	if ( (pcp_msg_info->lifetime < min_lifetime) && (pcp_msg_info->lifetime != 0) ) {
		pcp_msg_info->lifetime = min_lifetime;
	}

	return 0;
}

Project: miniupnp
File: pcpserver.c

static void parsePCPMAP_version1(const uint8_t *map_v1,
		pcp_info_t *pcp_msg_info)
{
	pcp_msg_info->is_map_op = 1;
	pcp_msg_info->protocol = map_v1[0];
	pcp_msg_info->int_port = READNU16(map_v1 + 4);
	pcp_msg_info->ext_port = READNU16(map_v1 + 6);

	pcp_msg_info->ext_ip = (struct in6_addr *)(map_v1 + 8);
}

Project: miniupnp
File: pcpserver.c

static void parsePCPMAP_version2(const uint8_t *map_v2,
		pcp_info_t *pcp_msg_info)
{
	pcp_msg_info->is_map_op = 1;
	memcpy(pcp_msg_info->nonce, map_v2, 12);
	pcp_msg_info->protocol = map_v2[12];
	pcp_msg_info->int_port = READNU16(map_v2 + 16);
	pcp_msg_info->ext_port = READNU16(map_v2 + 18);

	pcp_msg_info->ext_ip = (struct in6_addr *)(map_v2 + 20);
}

Project: miniupnp
File: pcpserver.c

static int parsePCPOption(uint8_t* pcp_buf, int remain, pcp_info_t *pcp_msg_info)
{
#ifdef DEBUG
	char third_addr[INET6_ADDRSTRLEN];
#endif /* DEBUG */
	unsigned short option_length;

	/* Do centralized option sanity checks here. */

	if (remain < (int)PCP_OPTION_HDR_SIZE) {
		pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
		return 0;
	}

	option_length = READNU16(pcp_buf + 2) + 4;	/* len */

	if (remain < option_length) {
		pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
		return 0;
	}

	switch (pcp_buf[0]) { /* code */

	case PCP_OPTION_3RD_PARTY:

		if (option_length != PCP_3RD_PARTY_OPTION_SIZE) {
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
			return 0;
		}
#ifdef DEBUG
		syslog(LOG_DEBUG, "PCP OPTION: \t Third party\n");
		syslog(LOG_DEBUG, "Third PARTY IP: \t %s\n", inet_ntop(AF_INET6,
		       pcp_buf + 4, third_addr, INET6_ADDRSTRLEN));
#endif
		if (pcp_msg_info->thirdp_ip ) {
			syslog(LOG_ERR, "PCP: THIRD PARTY OPTION was already present. \n");
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
			return 0;
		} else {
			pcp_msg_info->thirdp_ip = (struct in6_addr *)(pcp_buf + 4);
			pcp_msg_info->mapped_ip = (struct in6_addr *)(pcp_buf + 4);
		}
		break;

	case PCP_OPTION_PREF_FAIL:

		if (option_length != PCP_PREFER_FAIL_OPTION_SIZE) {
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
			return 0;
		}
#ifdef DEBUG
		syslog(LOG_DEBUG, "PCP OPTION: \t Prefer failure \n");
#endif
		if (pcp_msg_info->opcode != PCP_OPCODE_MAP) {
			syslog(LOG_DEBUG, "PCP: Unsupported OPTION for given OPCODE.\n");
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
		}
		if (pcp_msg_info->pfailure_present != 0 ) {
			syslog(LOG_DEBUG, "PCP: PREFER FAILURE OPTION was already present.\n");
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
		} else {
			pcp_msg_info->pfailure_present = 1;
		}
		break;

	case PCP_OPTION_FILTER:
		/* TODO fully implement filter */
		if (option_length != PCP_FILTER_OPTION_SIZE) {
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
			return 0;
		}
#ifdef DEBUG
		syslog(LOG_DEBUG, "PCP OPTION: \t Filter\n");
#endif
		if (pcp_msg_info->opcode != PCP_OPCODE_MAP) {
			syslog(LOG_ERR, "PCP: Unsupported OPTION for given OPCODE.\n");
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
			return 0;
		}
		break;

#ifdef PCP_FLOWP
	case PCP_OPTION_FLOW_PRIORITY:

#ifdef DEBUG
		syslog(LOG_DEBUG, "PCP OPTION: \t Flow priority\n");
#endif
		if (option_length != PCP_FLOW_PRIORITY_OPTION_SIZE) {
			syslog(LOG_ERR, "PCP: Error processing DSCP. sizeof %d and remaining %d. flow len %d \n",
			       PCP_FLOW_PRIORITY_OPTION_SIZE, remain, READNU16(pcp_buf + 2));
			pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
			return 0;
		}

#ifdef DEBUG
		syslog(LOG_DEBUG, "DSCP UP: \t %d\n", pcp_buf[4]);
		syslog(LOG_DEBUG, "DSCP DOWN: \t %d\n", pcp_buf[5]);
#endif
		pcp_msg_info->dscp_up = pcp_buf[4];
		pcp_msg_info->dscp_down = pcp_buf[5];
		pcp_msg_info->flowp_present = 1;

		break;
#endif
	default:
		if (pcp_buf[0] < 128) {
			syslog(LOG_ERR, "PCP: Unrecognized mandatory PCP OPTION: %d \n", (int)pcp_buf[0]);
			/* Mandatory to understand */
			pcp_msg_info->result_code = PCP_ERR_UNSUPP_OPTION;
			remain = 0;
			break;
		}
		/* TODO - log optional not understood options? */
		break;
	}
	return option_length;
}

Project: miniupnp
File: pcpserver.c

static void parsePCPOptions(void* pcp_buf, int remain, pcp_info_t *pcp_msg_info)
{
	int option_length;

	while (remain > 0) {
		option_length = parsePCPOption(pcp_buf, remain, pcp_msg_info);
		if (!option_length)
			break;
		remain -= option_length;
		pcp_buf += option_length;
	}
	if (remain > 0) {
		syslog(LOG_WARNING, "%s: remain=%d", "parsePCPOptions", remain);
	}
}

Project: miniupnp
File: pcpserver.c

static void parsePCPPEER_version1(const uint8_t *buf,
		pcp_info_t *pcp_msg_info)
{
	pcp_msg_info->is_peer_op = 1;
	pcp_msg_info->protocol = buf[0];
	pcp_msg_info->int_port = READNU16(buf + 4);
	pcp_msg_info->ext_port = READNU16(buf + 6);
	pcp_msg_info->peer_port = READNU16(buf + 24);

	pcp_msg_info->ext_ip = (struct in6_addr *)(buf + 8);
	pcp_msg_info->peer_ip = (struct in6_addr *)(buf + 28);
}

Project: miniupnp
File: pcpserver.c

static void parsePCPPEER_version2(const uint8_t *buf, pcp_info_t *pcp_msg_info)
{
	pcp_msg_info->is_peer_op = 1;
	memcpy(pcp_msg_info->nonce, buf, 12);
	pcp_msg_info->protocol = buf[12];
	pcp_msg_info->int_port = READNU16(buf + 16);
	pcp_msg_info->ext_port = READNU16(buf + 18);
	pcp_msg_info->peer_port = READNU16(buf + 36);

	pcp_msg_info->ext_ip = (struct in6_addr *)(buf + 20);
	pcp_msg_info->peer_ip = (struct in6_addr *)(buf + 40);
}

Project: miniupnp
File: pcpserver.c

static int parseSADSCP(const uint8_t *buf, pcp_info_t *pcp_msg_info)
{
	pcp_msg_info->delay_tolerance = (buf[12]>>6)&3;
	pcp_msg_info->loss_tolerance = (buf[12]>>4)&3;
	pcp_msg_info->jitter_tolerance = (buf[12]>>2)&3;

	if (pcp_msg_info->delay_tolerance == 3 ||
	    pcp_msg_info->loss_tolerance == 3 ||
	    pcp_msg_info->jitter_tolerance == 3 ) {
		pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
		return 1;
	}

	pcp_msg_info->app_name = (const char *)(buf + 14);
	pcp_msg_info->app_name_len = buf[13];

	return 0;
}

Project: miniupnp
File: pcpserver.c

static void printMAPOpcodeVersion1(const uint8_t *buf)
{
	char map_addr[INET6_ADDRSTRLEN];
	syslog(LOG_DEBUG, "PCP MAP: v1 Opcode specific information. \n");
	syslog(LOG_DEBUG, "MAP protocol: \t\t %d\n", (int)buf[0] );
	syslog(LOG_DEBUG, "MAP int port: \t\t %d\n", (int)READNU16(buf+4));
	syslog(LOG_DEBUG, "MAP ext port: \t\t %d\n", (int)READNU16(buf+6));
	syslog(LOG_DEBUG, "MAP Ext IP: \t\t %s\n", inet_ntop(AF_INET6,
	       buf+8, map_addr, INET6_ADDRSTRLEN));
}

Project: miniupnp
File: pcpserver.c

static void printPEEROpcodeVersion1(const uint8_t *buf)
{
	char ext_addr[INET6_ADDRSTRLEN];
	char peer_addr[INET6_ADDRSTRLEN];
	syslog(LOG_DEBUG, "PCP PEER: v1 Opcode specific information. \n");
	syslog(LOG_DEBUG, "Protocol: \t\t %d\n", (int)buf[0]);
	syslog(LOG_DEBUG, "Internal port: \t\t %d\n", READNU16(buf + 4));
	syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, buf + 8,
	       ext_addr,INET6_ADDRSTRLEN));
	syslog(LOG_DEBUG, "External port port: \t\t %d\n", READNU16(buf + 6));
	syslog(LOG_DEBUG, "PEER IP: \t\t %s\n", inet_ntop(AF_INET6, buf + 28,
	       peer_addr,INET6_ADDRSTRLEN));
	syslog(LOG_DEBUG, "PEER port port: \t\t %d\n", READNU16(buf + 24));
}

Project: miniupnp
File: pcpserver.c

static void printPEEROpcodeVersion2(const uint8_t *buf)
{
	char ext_addr[INET6_ADDRSTRLEN];
	char peer_addr[INET6_ADDRSTRLEN];

	syslog(LOG_DEBUG, "PCP PEER: v2 Opcode specific information.");
	syslog(LOG_DEBUG, "nonce:        \t%08x%08x%08x",
	       READNU32(buf), READNU32(buf+4), READNU32(buf+8));
	syslog(LOG_DEBUG, "Protocol:     \t%d", buf[12]);
	syslog(LOG_DEBUG, "Internal port:\t%d", READNU16(buf + 16));
	syslog(LOG_DEBUG, "External IP:  \t%s", inet_ntop(AF_INET6, buf + 20,
	       ext_addr, INET6_ADDRSTRLEN));
	syslog(LOG_DEBUG, "External port:\t%d", READNU16(buf + 18));
	syslog(LOG_DEBUG, "PEER IP:      \t%s", inet_ntop(AF_INET6, buf + 40,
	       peer_addr, INET6_ADDRSTRLEN));
	syslog(LOG_DEBUG, "PEER port:    \t%d", READNU16(buf + 36));
}

Project: miniupnp
File: pcpserver.c

static void printSADSCPOpcode(const uint8_t *buf)
{
	unsigned char sadscp_tol;
	sadscp_tol = buf[12];	/* tolerance_fields */

	syslog(LOG_DEBUG, "PCP SADSCP: Opcode specific information.\n");
	syslog(LOG_DEBUG, "Delay tolerance %d \n", (sadscp_tol>>6)&3);
	syslog(LOG_DEBUG, "Loss tolerance %d \n",  (sadscp_tol>>4)&3);
	syslog(LOG_DEBUG, "Jitter tolerance %d \n",  (sadscp_tol>>2)&3);
	syslog(LOG_DEBUG, "RRR %d \n", sadscp_tol&3);
	syslog(LOG_DEBUG, "AppName Length %d \n", buf[13]);
	syslog(LOG_DEBUG, "Application name %.*s \n", buf[13], buf + 14);
}

Project: miniupnp
File: pcpserver.c

static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
{
	int remainingSize;

	/* start with PCP_SUCCESS as result code,
	 * if everything is OK value will be unchanged */
	pcp_msg_info->result_code = PCP_SUCCESS;

	remainingSize = req_size;

	/* discard request that exceeds maximal length,
	   or that is shorter than PCP_MIN_LEN (=24)
	   or that is not the multiple of 4 */
	if (req_size < 3)
		return 0; /* ignore msg */

	if (req_size < PCP_MIN_LEN) {
		pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
		return 1; /* send response */
	}

	if ( (req_size > PCP_MAX_LEN) || ( (req_size & 3) != 0)) {
		syslog(LOG_ERR, "PCP: Size of PCP packet(%d) is larger than %d bytes or "
		       "the size is not multiple of 4.\n", req_size, PCP_MAX_LEN);
		pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
		return 1; /* send response */
	}

	/* first parse request header */
	if (parseCommonRequestHeader(req, pcp_msg_info) ) {
		return 1;
	}

	remainingSize -= PCP_COMMON_REQUEST_SIZE;
	req += PCP_COMMON_REQUEST_SIZE;

	if (pcp_msg_info->version == 1) {
		/* legacy PCP version 1 support */
		switch (pcp_msg_info->opcode) {
		case PCP_OPCODE_MAP:

			remainingSize -= PCP_MAP_V1_SIZE;
			if (remainingSize < 0) {
				pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
				return pcp_msg_info->result_code;
			}

#ifdef DEBUG
			printMAPOpcodeVersion1(req);
#endif /* DEBUG */
			parsePCPMAP_version1(req, pcp_msg_info);

			req += PCP_MAP_V1_SIZE;

			parsePCPOptions(req, remainingSize, pcp_msg_info);
			if (ValidatePCPMsg(pcp_msg_info)) {
				if (pcp_msg_info->lifetime == 0) {
					DeletePCPMap(pcp_msg_info);
				} else {
					CreatePCPMap(pcp_msg_info);
				}
			} else {
				syslog(LOG_ERR, "PCP: Invalid PCP v1 MAP message.");
				return pcp_msg_info->result_code;
			}
			break;

#ifdef PCP_PEER
		case PCP_OPCODE_PEER:

			remainingSize -= PCP_PEER_V1_SIZE;
			if (remainingSize < 0) {
				pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
				return pcp_msg_info->result_code;
			}

#ifdef DEBUG
			printPEEROpcodeVersion1(req);
#endif /* DEBUG */
			parsePCPPEER_version1(req, pcp_msg_info);

			req += PCP_PEER_V1_SIZE;

			parsePCPOptions(req, remainingSize, pcp_msg_info);

			if (ValidatePCPMsg(pcp_msg_info)) {
				if (pcp_msg_info->lifetime == 0) {
					DeletePCPPeer(pcp_msg_info);
				} else {
					CreatePCPPeer(pcp_msg_info);
				}
			} else {
				syslog(LOG_ERR, "PCP: Invalid PCP v1 PEER message.");
				 return pcp_msg_info->result_code;
			}


			break;
#endif /* PCP_PEER */
		default:
			pcp_msg_info->result_code = PCP_ERR_UNSUPP_OPCODE;
			break;
		}

	} else if (pcp_msg_info->version == 2) {
		/* RFC 6887 PCP support
		 * http://tools.ietf.org/html/rfc6887 */
		switch (pcp_msg_info->opcode) {
		case PCP_OPCODE_ANNOUNCE:
			/* should check PCP Client's IP Address in request */
			/* see http://tools.ietf.org/html/rfc6887#section-14.1 */
			break;
		case PCP_OPCODE_MAP:

			remainingSize -= PCP_MAP_V2_SIZE;
			if (remainingSize < 0) {
				pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
				return pcp_msg_info->result_code;
			}

#ifdef DEBUG
			printMAPOpcodeVersion2(req);
#endif /* DEBUG */
			parsePCPMAP_version2(req, pcp_msg_info);
			req += PCP_MAP_V2_SIZE;

			parsePCPOptions(req, remainingSize, pcp_msg_info);

			if (ValidatePCPMsg(pcp_msg_info)) {
				if (pcp_msg_info->lifetime == 0) {
					DeletePCPMap(pcp_msg_info);
				} else {
					CreatePCPMap(pcp_msg_info);
				}
			} else {
				syslog(LOG_ERR, "PCP: Invalid PCP v2 MAP message.");
				return pcp_msg_info->result_code;
			}


			break;

#ifdef PCP_PEER
		case PCP_OPCODE_PEER:

			remainingSize -= PCP_PEER_V2_SIZE;
			if (remainingSize < 0) {
				pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
				return pcp_msg_info->result_code;
			}

#ifdef DEBUG
			printPEEROpcodeVersion2(req);
#endif /* DEBUG */
			parsePCPPEER_version2(req, pcp_msg_info);
			req += PCP_PEER_V2_SIZE;

			if (pcp_msg_info->result_code != 0) {
				return pcp_msg_info->result_code;
			}

			parsePCPOptions(req, remainingSize, pcp_msg_info);

			if (ValidatePCPMsg(pcp_msg_info)) {
				if (pcp_msg_info->lifetime == 0) {
					DeletePCPPeer(pcp_msg_info);
				} else {
					CreatePCPPeer(pcp_msg_info);
				}
			} else {
				syslog(LOG_ERR, "PCP: Invalid PCP v2 PEER message.");
			}

		break;
#endif /* PCP_PEER */

#ifdef PCP_SADSCP
		case PCP_OPCODE_SADSCP:
			remainingSize -= PCP_SADSCP_REQ_SIZE;
			if (remainingSize < 0) {
				pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
				return pcp_msg_info->result_code;
			}

			remainingSize -= ((uint8_t *)req)[13];	/* app_name_length */
			if (remainingSize < 0) {
				pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
				return pcp_msg_info->result_code;
			}

#ifdef DEBUG
			printSADSCPOpcode(req);
#endif
			parseSADSCP(req, pcp_msg_info);
			req += PCP_SADSCP_REQ_SIZE;
			if (pcp_msg_info->result_code != 0) {
				return pcp_msg_info->result_code;
			}
			req += pcp_msg_info->app_name_len;

			get_dscp_value(pcp_msg_info);


			break;
#endif
		default:
			pcp_msg_info->result_code = PCP_ERR_UNSUPP_OPCODE;
			break;
		}
	} else {
		pcp_msg_info->result_code = PCP_ERR_UNSUPP_VERSION;
		return pcp_msg_info->result_code;
	}
	return 1;
}