blob: 28961fbc5cd1133a2a5521be350d3fd1e3e43f40 [file] [log] [blame]
/**
* @file pcp/pcp.c PCP protocol details
*
* Copyright (C) 2010 - 2016 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_mbuf.h>
#include <re_sa.h>
#include <re_list.h>
#include <re_pcp.h>
#include "pcp.h"
static const uint8_t pattern[12] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff};
int pcp_ipaddr_encode(struct mbuf *mb, const struct sa *sa)
{
int err = 0;
if (!mb || !sa)
return EINVAL;
switch (sa_af(sa)) {
case AF_INET:
err |= mbuf_write_mem(mb, pattern, sizeof(pattern));
err |= mbuf_write_mem(mb, (void *)&sa->u.in.sin_addr.s_addr,
4);
break;
#ifdef HAVE_INET6
case AF_INET6:
err |= mbuf_write_mem(mb, sa->u.in6.sin6_addr.s6_addr, 16);
break;
#endif
default:
err = EAFNOSUPPORT;
break;
}
return err;
}
int pcp_ipaddr_decode(struct mbuf *mb, struct sa *sa)
{
uint8_t *p;
if (!mb || !sa)
return EINVAL;
if (mbuf_get_left(mb) < 16)
return EBADMSG;
p = mbuf_buf(mb);
if (0 == memcmp(p, pattern, sizeof(pattern))) {
sa_init(sa, AF_INET);
memcpy(&sa->u.in.sin_addr, p + 12, 4);
}
#ifdef HAVE_INET6
else {
sa_init(sa, AF_INET6);
memcpy(sa->u.in6.sin6_addr.s6_addr, p, 16);
}
#endif
mb->pos += 16;
return 0;
}
const char *pcp_result_name(enum pcp_result result)
{
switch (result) {
case PCP_SUCCESS: return "SUCCESS";
case PCP_UNSUPP_VERSION: return "UNSUPP_VERSION";
case PCP_NOT_AUTHORIZED: return "NOT_AUTHORIZED";
case PCP_MALFORMED_REQUEST: return "MALFORMED_REQUEST";
case PCP_UNSUPP_OPCODE: return "UNSUPP_OPCODE";
case PCP_UNSUPP_OPTION: return "UNSUPP_OPTION";
case PCP_MALFORMED_OPTION: return "MALFORMED_OPTION";
case PCP_NETWORK_FAILURE: return "NETWORK_FAILURE";
case PCP_NO_RESOURCES: return "NO_RESOURCES";
case PCP_UNSUPP_PROTOCOL: return "UNSUPP_PROTOCOL";
case PCP_USER_EX_QUOTA: return "USER_EX_QUOTA";
case PCP_CANNOT_PROVIDE_EXTERNAL: return "CANNOT_PROVIDE_EXTERNAL";
case PCP_ADDRESS_MISMATCH: return "ADDRESS_MISMATCH";
case PCP_EXCESSIVE_REMOTE_PEERS: return "EXCESSIVE_REMOTE_PEERS";
case PCP_UNSUPP_FAMILY: return "UNSUPP_FAMILY";
default: return "?";
}
}
const char *pcp_opcode_name(enum pcp_opcode opcode)
{
switch (opcode) {
case PCP_ANNOUNCE: return "ANNOUNCE";
case PCP_MAP: return "MAP";
case PCP_PEER: return "PEER";
default: return "?";
}
}
const char *pcp_proto_name(int proto)
{
switch (proto) {
case IPPROTO_UDP: return "UDP";
case IPPROTO_TCP: return "TCP";
default: return "?";
}
}