cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vidtv_channel.c (13525B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Vidtv serves as a reference DVB driver and helps validate the existing APIs
      4 * in the media subsystem. It can also aid developers working on userspace
      5 * applications.
      6 *
      7 * This file contains the code for a 'channel' abstraction.
      8 *
      9 * When vidtv boots, it will create some hardcoded channels.
     10 * Their services will be concatenated to populate the SDT.
     11 * Their programs will be concatenated to populate the PAT
     12 * Their events will be concatenated to populate the EIT
     13 * For each program in the PAT, a PMT section will be created
     14 * The PMT section for a channel will be assigned its streams.
     15 * Every stream will have its corresponding encoder polled to produce TS packets
     16 * These packets may be interleaved by the mux and then delivered to the bridge
     17 *
     18 *
     19 * Copyright (C) 2020 Daniel W. S. Almeida
     20 */
     21
     22#include <linux/dev_printk.h>
     23#include <linux/ratelimit.h>
     24#include <linux/slab.h>
     25#include <linux/types.h>
     26
     27#include "vidtv_channel.h"
     28#include "vidtv_common.h"
     29#include "vidtv_encoder.h"
     30#include "vidtv_mux.h"
     31#include "vidtv_psi.h"
     32#include "vidtv_s302m.h"
     33
     34static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e)
     35{
     36	struct vidtv_encoder *tmp = NULL;
     37	struct vidtv_encoder *curr = e;
     38
     39	while (curr) {
     40		/* forward the call to the derived type */
     41		tmp = curr;
     42		curr = curr->next;
     43		tmp->destroy(tmp);
     44	}
     45}
     46
     47#define ENCODING_ISO8859_15 "\x0b"
     48#define TS_NIT_PID	0x10
     49
     50/*
     51 * init an audio only channel with a s302m encoder
     52 */
     53struct vidtv_channel
     54*vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id)
     55{
     56	const __be32 s302m_fid              = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER);
     57	char *event_text = ENCODING_ISO8859_15 "Bagatelle No. 25 in A minor for solo piano, also known as F\xfcr Elise, composed by Ludwig van Beethoven";
     58	char *event_name = ENCODING_ISO8859_15 "Ludwig van Beethoven: F\xfcr Elise";
     59	struct vidtv_s302m_encoder_init_args encoder_args = {};
     60	char *iso_language_code = ENCODING_ISO8859_15 "eng";
     61	char *provider = ENCODING_ISO8859_15 "LinuxTV.org";
     62	char *name = ENCODING_ISO8859_15 "Beethoven";
     63	const u16 s302m_es_pid              = 0x111; /* packet id for the ES */
     64	const u16 s302m_program_pid         = 0x101; /* packet id for PMT*/
     65	const u16 s302m_service_id          = 0x880;
     66	const u16 s302m_program_num         = 0x880;
     67	const u16 s302m_beethoven_event_id  = 1;
     68	struct vidtv_channel *s302m;
     69
     70	s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
     71	if (!s302m)
     72		return NULL;
     73
     74	s302m->name = kstrdup(name, GFP_KERNEL);
     75	if (!s302m->name)
     76		goto free_s302m;
     77
     78	s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id, false, true);
     79	if (!s302m->service)
     80		goto free_name;
     81
     82	s302m->service->descriptor = (struct vidtv_psi_desc *)
     83				     vidtv_psi_service_desc_init(NULL,
     84								 DIGITAL_RADIO_SOUND_SERVICE,
     85								 name,
     86								 provider);
     87	if (!s302m->service->descriptor)
     88		goto free_service;
     89
     90	s302m->transport_stream_id = transport_stream_id;
     91
     92	s302m->program = vidtv_psi_pat_program_init(NULL,
     93						    s302m_service_id,
     94						    s302m_program_pid);
     95	if (!s302m->program)
     96		goto free_service;
     97
     98	s302m->program_num = s302m_program_num;
     99
    100	s302m->streams = vidtv_psi_pmt_stream_init(NULL,
    101						   STREAM_PRIVATE_DATA,
    102						   s302m_es_pid);
    103	if (!s302m->streams)
    104		goto free_program;
    105
    106	s302m->streams->descriptor = (struct vidtv_psi_desc *)
    107				     vidtv_psi_registration_desc_init(NULL,
    108								      s302m_fid,
    109								      NULL,
    110								      0);
    111	if (!s302m->streams->descriptor)
    112		goto free_streams;
    113
    114	encoder_args.es_pid = s302m_es_pid;
    115
    116	s302m->encoders = vidtv_s302m_encoder_init(encoder_args);
    117	if (!s302m->encoders)
    118		goto free_streams;
    119
    120	s302m->events = vidtv_psi_eit_event_init(NULL, s302m_beethoven_event_id);
    121	if (!s302m->events)
    122		goto free_encoders;
    123	s302m->events->descriptor = (struct vidtv_psi_desc *)
    124				    vidtv_psi_short_event_desc_init(NULL,
    125								    iso_language_code,
    126								    event_name,
    127								    event_text);
    128	if (!s302m->events->descriptor)
    129		goto free_events;
    130
    131	if (head) {
    132		while (head->next)
    133			head = head->next;
    134
    135		head->next = s302m;
    136	}
    137
    138	return s302m;
    139
    140free_events:
    141	vidtv_psi_eit_event_destroy(s302m->events);
    142free_encoders:
    143	vidtv_s302m_encoder_destroy(s302m->encoders);
    144free_streams:
    145	vidtv_psi_pmt_stream_destroy(s302m->streams);
    146free_program:
    147	vidtv_psi_pat_program_destroy(s302m->program);
    148free_service:
    149	vidtv_psi_sdt_service_destroy(s302m->service);
    150free_name:
    151	kfree(s302m->name);
    152free_s302m:
    153	kfree(s302m);
    154
    155	return NULL;
    156}
    157
    158static struct vidtv_psi_table_eit_event
    159*vidtv_channel_eit_event_cat_into_new(struct vidtv_mux *m)
    160{
    161	/* Concatenate the events */
    162	const struct vidtv_channel *cur_chnl = m->channels;
    163	struct vidtv_psi_table_eit_event *curr = NULL;
    164	struct vidtv_psi_table_eit_event *head = NULL;
    165	struct vidtv_psi_table_eit_event *tail = NULL;
    166	struct vidtv_psi_desc *desc = NULL;
    167	u16 event_id;
    168
    169	if (!cur_chnl)
    170		return NULL;
    171
    172	while (cur_chnl) {
    173		curr = cur_chnl->events;
    174
    175		if (!curr)
    176			dev_warn_ratelimited(m->dev,
    177					     "No events found for channel %s\n",
    178					     cur_chnl->name);
    179
    180		while (curr) {
    181			event_id = be16_to_cpu(curr->event_id);
    182			tail = vidtv_psi_eit_event_init(tail, event_id);
    183			if (!tail) {
    184				vidtv_psi_eit_event_destroy(head);
    185				return NULL;
    186			}
    187
    188			desc = vidtv_psi_desc_clone(curr->descriptor);
    189			vidtv_psi_desc_assign(&tail->descriptor, desc);
    190
    191			if (!head)
    192				head = tail;
    193
    194			curr = curr->next;
    195		}
    196
    197		cur_chnl = cur_chnl->next;
    198	}
    199
    200	return head;
    201}
    202
    203static struct vidtv_psi_table_sdt_service
    204*vidtv_channel_sdt_serv_cat_into_new(struct vidtv_mux *m)
    205{
    206	/* Concatenate the services */
    207	const struct vidtv_channel *cur_chnl = m->channels;
    208
    209	struct vidtv_psi_table_sdt_service *curr = NULL;
    210	struct vidtv_psi_table_sdt_service *head = NULL;
    211	struct vidtv_psi_table_sdt_service *tail = NULL;
    212
    213	struct vidtv_psi_desc *desc = NULL;
    214	u16 service_id;
    215
    216	if (!cur_chnl)
    217		return NULL;
    218
    219	while (cur_chnl) {
    220		curr = cur_chnl->service;
    221
    222		if (!curr)
    223			dev_warn_ratelimited(m->dev,
    224					     "No services found for channel %s\n",
    225					     cur_chnl->name);
    226
    227		while (curr) {
    228			service_id = be16_to_cpu(curr->service_id);
    229			tail = vidtv_psi_sdt_service_init(tail,
    230							  service_id,
    231							  curr->EIT_schedule,
    232							  curr->EIT_present_following);
    233			if (!tail)
    234				goto free;
    235
    236			desc = vidtv_psi_desc_clone(curr->descriptor);
    237			if (!desc)
    238				goto free_tail;
    239			vidtv_psi_desc_assign(&tail->descriptor, desc);
    240
    241			if (!head)
    242				head = tail;
    243
    244			curr = curr->next;
    245		}
    246
    247		cur_chnl = cur_chnl->next;
    248	}
    249
    250	return head;
    251
    252free_tail:
    253	vidtv_psi_sdt_service_destroy(tail);
    254free:
    255	vidtv_psi_sdt_service_destroy(head);
    256	return NULL;
    257}
    258
    259static struct vidtv_psi_table_pat_program*
    260vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m)
    261{
    262	/* Concatenate the programs */
    263	const struct vidtv_channel *cur_chnl = m->channels;
    264	struct vidtv_psi_table_pat_program *curr = NULL;
    265	struct vidtv_psi_table_pat_program *head = NULL;
    266	struct vidtv_psi_table_pat_program *tail = NULL;
    267	u16 serv_id;
    268	u16 pid;
    269
    270	if (!cur_chnl)
    271		return NULL;
    272
    273	while (cur_chnl) {
    274		curr = cur_chnl->program;
    275
    276		if (!curr)
    277			dev_warn_ratelimited(m->dev,
    278					     "No programs found for channel %s\n",
    279					     cur_chnl->name);
    280
    281		while (curr) {
    282			serv_id = be16_to_cpu(curr->service_id);
    283			pid = vidtv_psi_get_pat_program_pid(curr);
    284			tail = vidtv_psi_pat_program_init(tail,
    285							  serv_id,
    286							  pid);
    287			if (!tail) {
    288				vidtv_psi_pat_program_destroy(head);
    289				return NULL;
    290			}
    291
    292			if (!head)
    293				head = tail;
    294
    295			curr = curr->next;
    296		}
    297
    298		cur_chnl = cur_chnl->next;
    299	}
    300	/* Add the NIT table */
    301	vidtv_psi_pat_program_init(tail, 0, TS_NIT_PID);
    302
    303	return head;
    304}
    305
    306/*
    307 * Match channels to their respective PMT sections, then assign the
    308 * streams
    309 */
    310static void
    311vidtv_channel_pmt_match_sections(struct vidtv_channel *channels,
    312				 struct vidtv_psi_table_pmt **sections,
    313				 u32 nsections)
    314{
    315	struct vidtv_psi_table_pmt *curr_section = NULL;
    316	struct vidtv_psi_table_pmt_stream *head = NULL;
    317	struct vidtv_psi_table_pmt_stream *tail = NULL;
    318	struct vidtv_psi_table_pmt_stream *s = NULL;
    319	struct vidtv_channel *cur_chnl = channels;
    320	struct vidtv_psi_desc *desc = NULL;
    321	u16 e_pid; /* elementary stream pid */
    322	u16 curr_id;
    323	u32 j;
    324
    325	while (cur_chnl) {
    326		for (j = 0; j < nsections; ++j) {
    327			curr_section = sections[j];
    328
    329			if (!curr_section)
    330				continue;
    331
    332			curr_id = be16_to_cpu(curr_section->header.id);
    333
    334			/* we got a match */
    335			if (curr_id == cur_chnl->program_num) {
    336				s = cur_chnl->streams;
    337
    338				/* clone the streams for the PMT */
    339				while (s) {
    340					e_pid = vidtv_psi_pmt_stream_get_elem_pid(s);
    341					tail = vidtv_psi_pmt_stream_init(tail,
    342									 s->type,
    343									 e_pid);
    344
    345					if (!head)
    346						head = tail;
    347
    348					desc = vidtv_psi_desc_clone(s->descriptor);
    349					vidtv_psi_desc_assign(&tail->descriptor,
    350							      desc);
    351
    352					s = s->next;
    353				}
    354
    355				vidtv_psi_pmt_stream_assign(curr_section, head);
    356				break;
    357			}
    358		}
    359
    360		cur_chnl = cur_chnl->next;
    361	}
    362}
    363
    364static void
    365vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry *e)
    366{
    367	struct vidtv_psi_desc_service_list_entry *tmp;
    368
    369	while (e) {
    370		tmp = e;
    371		e = e->next;
    372		kfree(tmp);
    373	}
    374}
    375
    376static struct vidtv_psi_desc_service_list_entry
    377*vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service *s)
    378{
    379	struct vidtv_psi_desc_service_list_entry *curr_e = NULL;
    380	struct vidtv_psi_desc_service_list_entry *head_e = NULL;
    381	struct vidtv_psi_desc_service_list_entry *prev_e = NULL;
    382	struct vidtv_psi_desc *desc = s->descriptor;
    383	struct vidtv_psi_desc_service *s_desc;
    384
    385	while (s) {
    386		while (desc) {
    387			if (s->descriptor->type != SERVICE_DESCRIPTOR)
    388				goto next_desc;
    389
    390			s_desc = (struct vidtv_psi_desc_service *)desc;
    391
    392			curr_e = kzalloc(sizeof(*curr_e), GFP_KERNEL);
    393			if (!curr_e) {
    394				vidtv_channel_destroy_service_list(head_e);
    395				return NULL;
    396			}
    397
    398			curr_e->service_id = s->service_id;
    399			curr_e->service_type = s_desc->service_type;
    400
    401			if (!head_e)
    402				head_e = curr_e;
    403			if (prev_e)
    404				prev_e->next = curr_e;
    405
    406			prev_e = curr_e;
    407
    408next_desc:
    409			desc = desc->next;
    410		}
    411		s = s->next;
    412	}
    413	return head_e;
    414}
    415
    416int vidtv_channel_si_init(struct vidtv_mux *m)
    417{
    418	struct vidtv_psi_desc_service_list_entry *service_list = NULL;
    419	struct vidtv_psi_table_pat_program *programs = NULL;
    420	struct vidtv_psi_table_sdt_service *services = NULL;
    421	struct vidtv_psi_table_eit_event *events = NULL;
    422
    423	m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id);
    424	if (!m->si.pat)
    425		return -ENOMEM;
    426
    427	m->si.sdt = vidtv_psi_sdt_table_init(m->network_id,
    428					     m->transport_stream_id);
    429	if (!m->si.sdt)
    430		goto free_pat;
    431
    432	programs = vidtv_channel_pat_prog_cat_into_new(m);
    433	if (!programs)
    434		goto free_sdt;
    435	services = vidtv_channel_sdt_serv_cat_into_new(m);
    436	if (!services)
    437		goto free_programs;
    438
    439	events = vidtv_channel_eit_event_cat_into_new(m);
    440	if (!events)
    441		goto free_services;
    442
    443	/* look for a service descriptor for every service */
    444	service_list = vidtv_channel_build_service_list(services);
    445	if (!service_list)
    446		goto free_events;
    447
    448	/* use these descriptors to build the NIT */
    449	m->si.nit = vidtv_psi_nit_table_init(m->network_id,
    450					     m->transport_stream_id,
    451					     m->network_name,
    452					     service_list);
    453	if (!m->si.nit)
    454		goto free_service_list;
    455
    456	m->si.eit = vidtv_psi_eit_table_init(m->network_id,
    457					     m->transport_stream_id,
    458					     programs->service_id);
    459	if (!m->si.eit)
    460		goto free_nit;
    461
    462	/* assemble all programs and assign to PAT */
    463	vidtv_psi_pat_program_assign(m->si.pat, programs);
    464
    465	/* assemble all services and assign to SDT */
    466	vidtv_psi_sdt_service_assign(m->si.sdt, services);
    467
    468	/* assemble all events and assign to EIT */
    469	vidtv_psi_eit_event_assign(m->si.eit, events);
    470
    471	m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat,
    472								     m->pcr_pid);
    473	if (!m->si.pmt_secs)
    474		goto free_eit;
    475
    476	vidtv_channel_pmt_match_sections(m->channels,
    477					 m->si.pmt_secs,
    478					 m->si.pat->num_pmt);
    479
    480	vidtv_channel_destroy_service_list(service_list);
    481
    482	return 0;
    483
    484free_eit:
    485	vidtv_psi_eit_table_destroy(m->si.eit);
    486free_nit:
    487	vidtv_psi_nit_table_destroy(m->si.nit);
    488free_service_list:
    489	vidtv_channel_destroy_service_list(service_list);
    490free_events:
    491	vidtv_psi_eit_event_destroy(events);
    492free_services:
    493	vidtv_psi_sdt_service_destroy(services);
    494free_programs:
    495	vidtv_psi_pat_program_destroy(programs);
    496free_sdt:
    497	vidtv_psi_sdt_table_destroy(m->si.sdt);
    498free_pat:
    499	vidtv_psi_pat_table_destroy(m->si.pat);
    500	return 0;
    501}
    502
    503void vidtv_channel_si_destroy(struct vidtv_mux *m)
    504{
    505	u32 i;
    506
    507	for (i = 0; i < m->si.pat->num_pmt; ++i)
    508		vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]);
    509
    510	vidtv_psi_pat_table_destroy(m->si.pat);
    511
    512	kfree(m->si.pmt_secs);
    513	vidtv_psi_sdt_table_destroy(m->si.sdt);
    514	vidtv_psi_nit_table_destroy(m->si.nit);
    515	vidtv_psi_eit_table_destroy(m->si.eit);
    516}
    517
    518int vidtv_channels_init(struct vidtv_mux *m)
    519{
    520	/* this is the place to add new 'channels' for vidtv */
    521	m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id);
    522
    523	if (!m->channels)
    524		return -ENOMEM;
    525
    526	return 0;
    527}
    528
    529void vidtv_channels_destroy(struct vidtv_mux *m)
    530{
    531	struct vidtv_channel *curr = m->channels;
    532	struct vidtv_channel *tmp = NULL;
    533
    534	while (curr) {
    535		kfree(curr->name);
    536		vidtv_psi_sdt_service_destroy(curr->service);
    537		vidtv_psi_pat_program_destroy(curr->program);
    538		vidtv_psi_pmt_stream_destroy(curr->streams);
    539		vidtv_channel_encoder_destroy(curr->encoders);
    540		vidtv_psi_eit_event_destroy(curr->events);
    541
    542		tmp = curr;
    543		curr = curr->next;
    544		kfree(tmp);
    545	}
    546}