Track SSRCs and sequence numbers. Sync between userspace and the kernel.

pull/110/head
Marc Soda 11 years ago
parent 65a358727c
commit 16b91847f9

@ -161,6 +161,7 @@ static int call_avpf2avp_rtcp(str *s, struct packet_stream *);
static int call_savpf2avp_rtcp(str *s, struct packet_stream *);
//static int call_savpf2savp_rtcp(str *s, struct packet_stream *);
static void unkernelize(struct packet_stream *);
/* ********** */
@ -435,6 +436,7 @@ void kernelize(struct packet_stream *stream) {
reti.src_addr.family = reti.dst_addr.family;
reti.src_addr.port = sink->sfd->fd.localport;
reti.ssrc = sink->crypto.ssrc;
ifa = g_atomic_pointer_get(&sink->media->local_address);
if (reti.src_addr.family == AF_INET)
@ -860,6 +862,12 @@ kernel_check:
if (PS_ISSET(stream, NO_KERNEL_SUPPORT))
goto forward;
if (sink && sink->crypto.ssrc_mismatch && !stun_ret) {
ilog(LOG_INFO, "SSRC changed, unkernelizing media stream");
__unkernelize(stream);
goto forward;
}
if (PS_ISSET(stream, CONFIRMED) && sink && PS_ARESET2(sink, CONFIRMED, FILLED))
kernelize(stream);
@ -1378,6 +1386,7 @@ static void callmaster_timer(void *ptr) {
struct stream_fd *sfd;
struct rtp_stats *rs;
unsigned int pt;
struct rtp_ssrc_entry *cur_ssrc;
ZERO(hlp);
@ -1444,6 +1453,11 @@ static void callmaster_timer(void *ptr) {
mutex_lock(&sink->out_lock);
if (sink->crypto.params.crypto_suite
&& ke->target.encrypt.last_index - sink->crypto.last_index > 0x4000) {
// Keep the SSRC list in sync too.
cur_ssrc = find_ssrc(ke->target.ssrc, sink->crypto.ssrc_list);
if (cur_ssrc)
cur_ssrc->index = ke->target.encrypt.last_index;
sink->crypto.last_index = ke->target.encrypt.last_index;
update = 1;
}
@ -2931,6 +2945,7 @@ void call_destroy(struct call *c) {
dtls_shutdown(ps);
ps->sfd = NULL;
crypto_cleanup(&ps->crypto);
free_ssrc_list(ps->crypto.ssrc_list);
ps->rtp_sink = NULL;
ps->rtcp_sink = NULL;

@ -572,3 +572,36 @@ void crypto_dump_keys(struct crypto_context *in, struct crypto_context *out) {
ilog(LOG_DEBUG, "SRTP keys, outgoing:");
dump_key(out);
}
struct rtp_ssrc_entry *find_ssrc(u_int32_t ssrc, struct rtp_ssrc_entry *list) {
for (; list; list = list->next) {
if (list->ssrc == ssrc)
return list;
}
return 0;
}
void add_ssrc_entry(struct rtp_ssrc_entry *ent, struct rtp_ssrc_entry *list) {
struct rtp_ssrc_entry *cur;
for (cur = list; list; list = list->next)
cur = list;
cur->next = ent;
}
struct rtp_ssrc_entry *create_ssrc_entry(u_int32_t ssrc, u_int64_t index) {
struct rtp_ssrc_entry *ent;
ent = malloc(sizeof(struct rtp_ssrc_entry));
ent->ssrc = ssrc;
ent->index = index;
ent->next = 0;
return ent;
}
void free_ssrc_list(struct rtp_ssrc_entry *list) {
struct rtp_ssrc_entry *tmp;
for (tmp = list; tmp; ) {
tmp = list->next;
free(list);
list = tmp;
}
}

@ -88,10 +88,16 @@ struct crypto_context {
void *session_key_ctx[2];
int have_session_key:1;
};
struct rtp_ssrc_entry *ssrc_list;
int ssrc_mismatch;
};
struct rtp_ssrc_entry {
u_int32_t ssrc;
u_int64_t index;
struct rtp_ssrc_entry *next;
};
extern const struct crypto_suite crypto_suites[];
extern const int num_crypto_suites;
@ -102,7 +108,10 @@ const struct crypto_suite *crypto_find_suite(const str *);
int crypto_gen_session_key(struct crypto_context *, str *, unsigned char, int);
void crypto_dump_keys(struct crypto_context *in, struct crypto_context *out);
struct rtp_ssrc_entry *find_ssrc(u_int32_t, struct rtp_ssrc_entry *);
void add_ssrc_entry(struct rtp_ssrc_entry *, struct rtp_ssrc_entry *);
struct rtp_ssrc_entry *create_ssrc_entry(u_int32_t, u_int64_t);
void free_ssrc_list(struct rtp_ssrc_entry *);
INLINE int crypto_encrypt_rtp(struct crypto_context *c, struct rtp_header *rtp,

@ -182,26 +182,41 @@ void rtp_append_mki(str *s, struct crypto_context *c) {
int rtp_avp2savp(str *s, struct crypto_context *c) {
struct rtp_header *rtp;
str payload, to_auth;
u_int64_t index;
struct rtp_ssrc_entry *cur_ssrc;
if (rtp_payload(&rtp, &payload, s))
return -1;
if (check_session_keys(c))
return -1;
/* SSRC is part of the crypto context and ROC must be reset when it changes */
if (G_UNLIKELY(!c->ssrc_list))
c->ssrc_list = create_ssrc_entry(rtp->ssrc, ntohs(rtp->seq_num));
// Find the entry for the current SSRC.
cur_ssrc = find_ssrc(rtp->ssrc, c->ssrc_list);
// If it doesn't exist, create a new entry.
if (G_UNLIKELY(!cur_ssrc)) {
cur_ssrc = create_ssrc_entry(rtp->ssrc, ntohs(rtp->seq_num));
add_ssrc_entry(cur_ssrc, c->ssrc_list);
}
// New SSRC, set the crypto context.
if (G_UNLIKELY(!c->ssrc))
c->ssrc = rtp->ssrc;
// SSRC has changed.
else if (G_UNLIKELY(c->ssrc != rtp->ssrc)) {
c->last_index = 0;
// Signal stream_packet() to unkernelize.
c->ssrc_mismatch = 1;
c->ssrc = rtp->ssrc;
c->last_index = cur_ssrc->index;
} else {
c->ssrc_mismatch = 0;
}
index = packet_index(c, rtp);
cur_ssrc->index = packet_index(c, rtp);
/* rfc 3711 section 3.1 */
if (!c->params.session_params.unencrypted_srtp && crypto_encrypt_rtp(c, rtp, &payload, index))
if (!c->params.session_params.unencrypted_srtp && crypto_encrypt_rtp(c, rtp, &payload, cur_ssrc->index))
return -1;
to_auth = *s;
@ -209,7 +224,7 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
rtp_append_mki(s, c);
if (!c->params.session_params.unauthenticated_srtp && c->params.crypto_suite->srtp_auth_tag) {
c->params.crypto_suite->hash_rtp(c, s->s + s->len, &to_auth, index);
c->params.crypto_suite->hash_rtp(c, s->s + s->len, &to_auth, cur_ssrc->index);
s->len += c->params.crypto_suite->srtp_auth_tag;
}

@ -141,6 +141,7 @@ struct re_crypto_context {
struct crypto_shash *shash;
const struct re_cipher *cipher;
const struct re_hmac *hmac;
u_int32_t ssrc;
};
struct rtpengine_stats_a {
@ -1891,6 +1892,12 @@ static u_int64_t packet_index(struct re_crypto_context *c,
long long int diff;
unsigned long flags;
// Keep the crypt context SSRC in sync.
if (unlikely(!c->ssrc))
c->ssrc = rtp->ssrc;
else if (unlikely(c->ssrc != rtp->ssrc))
c->ssrc = rtp->ssrc;
seq = ntohs(rtp->seq_num);
spin_lock_irqsave(&c->lock, flags);
@ -2271,6 +2278,9 @@ src_check_ok:
if (pkt_idx != pkt_idx_u)
update_packet_index(&g->decrypt, &g->target.decrypt, pkt_idx);
} else {
// Pass to userspace if SSRC has changed.
if ((g->encrypt.ssrc) && (g->encrypt.ssrc != rtp.header->ssrc))
goto skip_error;
pkt_idx_u = pkt_idx = packet_index(&g->encrypt, &g->target.encrypt, rtp.header);
if (pkt_idx != pkt_idx_u)

@ -82,6 +82,7 @@ struct rtpengine_target_info {
struct rtpengine_srtp decrypt;
struct rtpengine_srtp encrypt;
u_int32_t ssrc; // Expose the SSRC to userspace when we resync.
unsigned char payload_types[NUM_PAYLOAD_TYPES]; /* must be sorted */
unsigned int num_payload_types;

Loading…
Cancel
Save