blob: a98d5d4b2d4989bb1b0791a890288dac9cf4be3f [file] [log] [blame]
/**
* @file re_pcp.h PCP - Port Control Protocol (RFC 6887)
*
* Copyright (C) 2010 - 2014 Creytiv.com
*/
/*
* The following specifications are implemented:
*
* RFC 6887
* draft-ietf-pcp-description-option-02
* draft-cheshire-pcp-unsupp-family
*
*/
/** PCP Version numbers */
enum {
PCP_VERSION = 2,
};
/* PCP port numbers */
enum {
PCP_PORT_CLI = 5350, /* for ANNOUNCE notifications */
PCP_PORT_SRV = 5351,
};
/** PCP Protocol sizes */
enum {
PCP_HDR_SZ = 24,
PCP_NONCE_SZ = 12,
PCP_MAP_SZ = 36,
PCP_PEER_SZ = 56,
PCP_MIN_PACKET = 24,
PCP_MAX_PACKET = 1100
};
enum pcp_opcode {
PCP_ANNOUNCE = 0,
PCP_MAP = 1,
PCP_PEER = 2,
};
enum pcp_result {
PCP_SUCCESS = 0,
PCP_UNSUPP_VERSION = 1,
PCP_NOT_AUTHORIZED = 2,
PCP_MALFORMED_REQUEST = 3,
PCP_UNSUPP_OPCODE = 4,
PCP_UNSUPP_OPTION = 5,
PCP_MALFORMED_OPTION = 6,
PCP_NETWORK_FAILURE = 7,
PCP_NO_RESOURCES = 8,
PCP_UNSUPP_PROTOCOL = 9,
PCP_USER_EX_QUOTA = 10,
PCP_CANNOT_PROVIDE_EXTERNAL = 11,
PCP_ADDRESS_MISMATCH = 12,
PCP_EXCESSIVE_REMOTE_PEERS = 13,
PCP_UNSUPP_FAMILY = 14 /*draft-cheshire-pcp-unsupp-family*/
};
enum pcp_option_code {
PCP_OPTION_THIRD_PARTY = 1,
PCP_OPTION_PREFER_FAILURE = 2,
PCP_OPTION_FILTER = 3,
PCP_OPTION_DESCRIPTION = 128, /* RFC 7220 */
};
/* forward declarations */
struct udp_sock;
/** Defines a PCP option */
struct pcp_option {
struct le le;
enum pcp_option_code code;
union {
struct sa third_party; /* Internal IP-address */
struct pcp_option_filter {
uint8_t prefix_length;
struct sa remote_peer;
} filter;
char *description;
} u;
};
/**
* Defines a complete and decoded PCP request/response.
*
* A PCP message consist of a header, and optional payload and options:
*
* [ Header ]
* ( Opcode Payload )
* ( PCP Options )
*
*/
struct pcp_msg {
/** PCP Common Header */
struct pcp_hdr {
uint8_t version; /**< PCP Protocol version 2 */
unsigned resp:1; /**< R-bit; 0=Request, 1=Response */
uint8_t opcode; /**< A 7-bit opcode */
uint32_t lifetime; /**< Lifetime in [seconds] */
/* request: */
struct sa cli_addr; /**< Client's IP Address (SA_ADDR) */
/* response: */
enum pcp_result result; /**< Result code for this response */
uint32_t epoch; /**< Server's Epoch Time [seconds] */
} hdr;
/** PCP Opcode-specific payload */
union pcp_payload {
struct pcp_map {
uint8_t nonce[PCP_NONCE_SZ]; /**< Mapping Nonce */
uint8_t proto; /**< IANA protocol */
uint16_t int_port; /**< Internal Port */
struct sa ext_addr; /**< External Address */
} map;
struct pcp_peer {
struct pcp_map map; /**< Common with MAP */
struct sa remote_addr; /**< Remote address */
} peer;
} pld;
/** List of PCP Options (struct pcp_option) */
struct list optionl;
};
/** PCP request configuration */
struct pcp_conf {
uint32_t irt; /**< Initial retransmission time [seconds] */
uint32_t mrc; /**< Maximum retransmission count */
uint32_t mrt; /**< Maximum retransmission time [seconds] */
uint32_t mrd; /**< Maximum retransmission duration [seconds] */
};
/* request */
struct pcp_request;
typedef void (pcp_resp_h)(int err, struct pcp_msg *msg, void *arg);
int pcp_request(struct pcp_request **reqp, const struct pcp_conf *conf,
const struct sa *pcp_server, enum pcp_opcode opcode,
uint32_t lifetime, const void *payload,
pcp_resp_h *resph, void *arg, uint32_t optionc, ...);
void pcp_force_refresh(struct pcp_request *req);
/* reply */
int pcp_reply(struct udp_sock *us, const struct sa *dst, struct mbuf *req,
enum pcp_opcode opcode, enum pcp_result result,
uint32_t lifetime, uint32_t epoch_time, const void *payload);
/* msg */
typedef bool (pcp_option_h)(const struct pcp_option *opt, void *arg);
int pcp_msg_decode(struct pcp_msg **msgp, struct mbuf *mb);
int pcp_msg_printhdr(struct re_printf *pf, const struct pcp_msg *msg);
int pcp_msg_print(struct re_printf *pf, const struct pcp_msg *msg);
struct pcp_option *pcp_msg_option(const struct pcp_msg *msg,
enum pcp_option_code code);
struct pcp_option *pcp_msg_option_apply(const struct pcp_msg *msg,
pcp_option_h *h, void *arg);
const void *pcp_msg_payload(const struct pcp_msg *msg);
/* option */
int pcp_option_encode(struct mbuf *mb, enum pcp_option_code code,
const void *v);
int pcp_option_decode(struct pcp_option **optp, struct mbuf *mb);
int pcp_option_print(struct re_printf *pf, const struct pcp_option *opt);
/* encode */
int pcp_msg_req_vencode(struct mbuf *mb, enum pcp_opcode opcode,
uint32_t lifetime, const struct sa *cli_addr,
const void *payload, uint32_t optionc, va_list ap);
int pcp_msg_req_encode(struct mbuf *mb, enum pcp_opcode opcode,
uint32_t lifetime, const struct sa *cli_addr,
const void *payload, uint32_t optionc, ...);
/* pcp */
int pcp_ipaddr_encode(struct mbuf *mb, const struct sa *sa);
int pcp_ipaddr_decode(struct mbuf *mb, struct sa *sa);
const char *pcp_result_name(enum pcp_result result);
const char *pcp_opcode_name(enum pcp_opcode opcode);
const char *pcp_proto_name(int proto);