#define MODULE_LOG_PREFIX "camd35" #include "globals.h" #include "oscam-array.h" #if defined(CS_CACHEEX) && (defined(MODULE_CAMD35) || defined(MODULE_CAMD35_TCP)) #include "module-cacheex.h" #include "module-camd35.h" #include "module-camd35-cacheex.h" #include "oscam-cache.h" #include "oscam-client.h" #include "oscam-ecm.h" #include "oscam-string.h" #include "oscam-reader.h" #ifdef CS_CACHEEX_AIO #include "oscam-chk.h" #include "oscam-config.h" #endif uint8_t camd35_node_id[8]; #define CSP_HASH_SWAP(n) (((((uint32_t)(n) & 0xFF)) << 24) | \ ((((uint32_t)(n) & 0xFF00)) << 8) | \ ((((uint32_t)(n) & 0xFF0000)) >> 8) | \ ((((uint32_t)(n) & 0xFF000000)) >> 24)) #ifdef CS_CACHEEX_AIO void camd35_cacheex_feature_trigger_in(struct s_client *cl, uint8_t *buf) { int32_t feature = 0; uint16_t i = 20; uint8_t filter_count; uint8_t j, k, l, rc; feature = buf[21] | (buf[20] << 8); FTAB *lgonly_tab; // check client & cacheex-mode if( !check_client(cl) || !( (cl->typ == 'c' && cl->account->cacheex.mode > 0) || (cl->typ == 'p' && cl->reader->cacheex.mode > 0) ) ) { return; } switch(feature) { // set localgenerated only case 1: if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) { if(cfg.cacheex_lg_only_remote_settings || cl->account->cacheex.lg_only_remote_settings) cl->account->cacheex.localgenerated_only = buf[24]; else if(buf[24]) cl->account->cacheex.localgenerated_only = buf[24]; } else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) { if(cfg.cacheex_lg_only_remote_settings || cl->reader->cacheex.lg_only_remote_settings) cl->reader->cacheex.localgenerated_only = buf[24]; else if(buf[24]) cl->reader->cacheex.localgenerated_only = buf[24]; } break; // set localgenerated only caidtab case 2: filter_count = buf[i+4]; i += 5; memset(&lgonly_tab, 0, sizeof(lgonly_tab)); if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) { lgonly_tab = &cl->account->cacheex.lg_only_tab; } else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) { lgonly_tab = &cl->reader->cacheex.lg_only_tab; } else { return; } // remotesettings enabled - replace local settings if(cfg.cacheex_lg_only_remote_settings || ( (cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.lg_only_remote_settings) || (cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.lg_only_remote_settings) ) ) { ftab_clear(lgonly_tab); for(j = 0; j < filter_count; j++) { FILTER d; memset(&d, 0, sizeof(d)); d.caid = b2i(2, buf + i); i += 2; d.nprids = 1; d.prids[0] = NO_PROVID_VALUE; ftab_add(lgonly_tab, &d); } } // remotesettings disabled - write additional remote-caids received else { for(j = 0; j < filter_count; j++) { FILTER d; memset(&d, 0, sizeof(d)); d.caid = b2i(2, buf + i); i += 2; d.nprids = 1; d.prids[0] = NO_PROVID_VALUE; if(!chk_lg_only_cp(d.caid, d.prids[0], lgonly_tab)) { cs_log_dbg(D_CACHEEX, "%04X:%06X not found in local settings - adding them", d.caid, d.prids[0]); for(l = rc = 0; (!rc) && (l < lgonly_tab->nfilts); l++) { if(lgonly_tab->filts[l].caid == d.caid) { rc = 1; if(lgonly_tab->filts[l].nprids+1 <= CS_MAXPROV) { lgonly_tab->filts[l].prids[lgonly_tab->filts[l].nprids] = d.prids[0]; lgonly_tab->filts[l].nprids++; } else { cs_log_dbg(D_CACHEEX, "error: cacheex_lg_only_tab -> max. number(%i) of providers reached", CS_MAXPROV); } } } if(!rc) { ftab_add(lgonly_tab, &d); } } } } break; // set cacheex_ecm_filter - extended case 4: filter_count = buf[i+4]; i += 5; CECSPVALUETAB *filter; memset(&filter, 0, sizeof(filter)); if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.allow_filter) { filter = &cl->account->cacheex.filter_caidtab; } else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.allow_filter) { filter = &cl->reader->cacheex.filter_caidtab; } else { return; } cecspvaluetab_clear(filter); for(j = 0; j < filter_count; j++) { int32_t caid = -1, cmask = -1, provid = -1, srvid = -1; CECSPVALUETAB_DATA d; memset(&d, 0, sizeof(d)); caid = b2i(2, buf + i); if(caid == 0xFFFF) caid = -1; i += 2; cmask = b2i(2, buf + i); if(cmask == 0xFFFF) cmask = -1; i += 2; provid = b2i(3, buf + i); if(provid == 0xFFFFFF) provid = -1; i += 3; srvid = b2i(2, buf + i); if(srvid == 0xFFFF) srvid = -1; i += 2; if(caid > 0) { d.caid = caid; d.cmask = cmask; d.prid = provid; d.srvid = srvid; cecspvaluetab_add(filter, &d); } } break; // no push after case 8: ; CAIDVALUETAB *ctab; memset(&ctab, 0, sizeof(ctab)); if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) { ctab = &cl->account->cacheex.cacheex_nopushafter_tab; } else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) { ctab = &cl->reader->cacheex.cacheex_nopushafter_tab; } else { return; } filter_count = buf[i+4]; i += 5; caidvaluetab_clear(ctab); for(j = 0; j < filter_count; j++) { uint16_t caid = 0, value = 0; CAIDVALUETAB_DATA d; memset(&d, 0, sizeof(d)); caid = b2i(2, buf + i); if(caid == 0xFFFF) caid = -1; i += 2; value = b2i(2, buf + i); if(value == 0xFFFF) value = -1; i += 2; if(caid > 0) { d.caid = caid; d.value = value; caidvaluetab_add(ctab, &d); } } break; // max hop case 16: if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.allow_maxhop) { cl->account->cacheex.maxhop = buf[24]; cl->account->cacheex.maxhop_lg = buf[25]; } else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.allow_maxhop) { cl->reader->cacheex.maxhop = buf[24]; cl->reader->cacheex.maxhop_lg = buf[25]; } break; // aio-version case 32: ; uint16_t payload_size = b2i(2, buf + i + 2); if(cl->typ == 'c' && cl->account->cacheex.mode > 0) { char *ofs = (char *)buf + i + 4; memset(cl->account->cacheex.aio_version, 0, sizeof(cl->account->cacheex.aio_version)); if(payload_size > 0) { size_t str_len = strnlen(ofs, payload_size); if(str_len >= sizeof(cl->account->cacheex.aio_version)) str_len = sizeof(cl->account->cacheex.aio_version) - 1; memcpy(cl->account->cacheex.aio_version, ofs, str_len); // sanitize: remove non-printable characters size_t x; for(x = 0; x < str_len; x++) { if(cl->account->cacheex.aio_version[x] < 0x20 || cl->account->cacheex.aio_version[x] > 0x7E) { cl->account->cacheex.aio_version[x] = '\0'; break; } } } } else if(cl->typ == 'p' && cl->reader->cacheex.mode > 0) { char *ofs = (char *)buf + i + 4; memset(cl->reader->cacheex.aio_version, 0, sizeof(cl->reader->cacheex.aio_version)); if(payload_size > 0) { size_t str_len = strnlen(ofs, payload_size); if(str_len >= sizeof(cl->reader->cacheex.aio_version)) str_len = sizeof(cl->reader->cacheex.aio_version) - 1; memcpy(cl->reader->cacheex.aio_version, ofs, str_len); // sanitize: remove non-printable characters size_t x; for(x = 0; x < str_len; x++) { if(cl->reader->cacheex.aio_version[x] < 0x20 || cl->reader->cacheex.aio_version[x] > 0x7E) { cl->reader->cacheex.aio_version[x] = '\0'; break; } } } } break; // lg_only_tab caid:prov1[,provN][;caid:prov] case 64: ; memset(&lgonly_tab, 0, sizeof(lgonly_tab)); if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) { lgonly_tab = &cl->account->cacheex.lg_only_tab; } else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) { lgonly_tab = &cl->reader->cacheex.lg_only_tab; } else { return; } filter_count = buf[i+4]; i += 5; // remotesettings enabled - replace local settings if(cfg.cacheex_lg_only_remote_settings || ( (cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.lg_only_remote_settings) || (cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.lg_only_remote_settings) || !lgonly_tab->nfilts ) ) { ftab_clear(lgonly_tab); for(j = 0; j < filter_count; j++) { FILTER d; memset(&d, 0, sizeof(d)); d.caid = b2i(2, buf + i); i += 2; d.nprids = b2i(1, buf + i); i += 1; for(k=0; k < d.nprids; k++) { d.prids[k] = b2i(3, buf + i); i += 3; } ftab_add(lgonly_tab, &d); } } // remotesettings disabled - write additional remote-caid/provids received else { for(j = 0; j < filter_count; j++) { FILTER d; memset(&d, 0, sizeof(d)); d.caid = b2i(2, buf + i); i += 2; d.nprids = b2i(1, buf + i); i += 1; for(k=0; k < d.nprids; k++) { d.prids[k] = b2i(3, buf + i); i += 3; if(!chk_ident_filter(d.caid, d.prids[k], lgonly_tab)) { cs_log_dbg(D_CACHEEX, "%04X:%06X not found in local settings - adding them", d.caid, d.prids[k]); for(l = rc = 0; (!rc) && (l < lgonly_tab->nfilts); l++) { if(lgonly_tab->filts[l].caid == d.caid) { rc = 1; if(lgonly_tab->filts[l].nprids+1 <= CS_MAXPROV) { lgonly_tab->filts[l].prids[lgonly_tab->filts[l].nprids] = d.prids[k]; lgonly_tab->filts[l].nprids++; } else { cs_log_dbg(D_CACHEEX, "error: cacheex_lg_only_tab -> max. number of providers reached"); } } } if(!rc) { ftab_add(lgonly_tab, &d); } } } } } break; default: return; } } void camd35_cacheex_feature_trigger(struct s_client *cl, int32_t feature, uint8_t mode) { // size: 20 + (feature-bitfield & mask: 2) + payload-size: 2 + feature-payload :x uint16_t size = 20 + 2 + 2; int i = 0; uint8_t j; uint8_t payload[MAX_ECM_SIZE-size]; memset(payload, 0, sizeof(payload)); // check client & cacheex-mode if(!check_client(cl)) { return; } switch(feature) { FTAB *lgonly_tab; // set localgenerated only case 1: size += 1; if(size < 32) size = 32; // bitfield i2b_buf(2, feature, payload + i); i += 2; // payload-size i2b_buf(2, 1, payload + i); i += 2; // set payload if(mode == 2) { if(cl->reader->cacheex.localgenerated_only_in) payload[i] = cl->reader->cacheex.localgenerated_only_in; else payload[i] = cfg.cacheex_localgenerated_only_in; } else if(mode == 3) { if(cl->account->cacheex.localgenerated_only_in) payload[i] = cl->account->cacheex.localgenerated_only_in; else payload[i] = cfg.cacheex_localgenerated_only_in; } break; // set localgenerated only caidtab; cx-aio < 9.2.6-04 case 2: ; if(mode == 2) { lgonly_tab = &cl->reader->cacheex.lg_only_in_tab; if(!lgonly_tab->nfilts) lgonly_tab = &cfg.cacheex_lg_only_in_tab; } else if(mode == 3) { lgonly_tab = &cl->account->cacheex.lg_only_in_tab; if(!lgonly_tab->nfilts) lgonly_tab = &cfg.cacheex_lg_only_in_tab; } else { return; } size += (lgonly_tab->nfilts * 2 + 1); if(size < 32) size = 32; // bitfield i2b_buf(2, feature, payload + i); i += 2; // payload-size if((lgonly_tab->nfilts * 2 + 1) > (int)sizeof(payload)) { cs_log_dbg(D_CACHEEX, "ERROR: too much localgenerated only caidtab-entries (max. 255)"); return; } i2b_buf(2, (lgonly_tab->nfilts * 2 + 1), payload + i); // n * caid + ctnum i += 2; // set payload if(lgonly_tab->nfilts > 255) { cs_log_dbg(D_CACHEEX, "ERROR: too much localgenerated only caidtab-entries (max. 255)"); return; } payload[i] = lgonly_tab->nfilts; i += 1; for(j = 0; j < lgonly_tab->nfilts; j++) { FILTER *d = &lgonly_tab->filts[j]; if(d->caid) { i2b_buf(2, d->caid, payload + i); i += 2; } else { continue; } } break; // cacchex_ecm_filter extendend case 4: ; CECSPVALUETAB *filter; if(mode == 2) { filter = &cl->reader->cacheex.filter_caidtab; // if not set, use global settings if(cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0) filter = &cfg.cacheex_filter_caidtab; // if aio, use global aio settings if(cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && cl->cacheex_aio_checked && (cl->reader->cacheex.feature_bitfield & 4)) filter = &cfg.cacheex_filter_caidtab_aio; } else if(mode == 3) { filter = &cl->account->cacheex.filter_caidtab; // if not set, use global settings if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0) filter = &cfg.cacheex_filter_caidtab; if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && cl->cacheex_aio_checked && (cl->account->cacheex.feature_bitfield & 4)) filter = &cfg.cacheex_filter_caidtab_aio; } else { return; } size += (filter->cevnum * 9 + 1); if(size < 32) size = 32; // bitfield i2b_buf(2, feature, payload + i); i += 2; // payload-size if((filter->cevnum * 9 + 1) > (int)sizeof(payload)) { cs_log_dbg(D_CACHEEX, "ERROR: to much cacheex_ecm_filter-entries (max. 63), only 15 default camd3-filters sent"); return; } i2b_buf(2, (filter->cevnum * 9 + 1), payload + i); // n * (caid2,mask2,provid3,srvid2) + ctnum1 i += 2; // set payload payload[i] = filter->cevnum; i += 1; for(j = 0; j < filter->cevnum; j++) { CECSPVALUETAB_DATA *d = &filter->cevdata[j]; if(d->caid) { i2b_buf(2, d->caid, payload + i); i += 2; } if(d->cmask) { i2b_buf(2, d->cmask, payload + i); } i += 2; if(d->prid) { i2b_buf(3, d->prid, payload + i); } i += 3; if(d->srvid) { i2b_buf(2, d->srvid, payload + i); } i += 2; } camd35_cacheex_send_push_filter(cl, 2); break; // no push after case 8: ; CAIDVALUETAB *ctab; if(mode == 2) { ctab = &cl->reader->cacheex.cacheex_nopushafter_tab; if(!ctab->cvnum) ctab = &cfg.cacheex_nopushafter_tab; } else if(mode == 3) { ctab = &cl->account->cacheex.cacheex_nopushafter_tab; if(!ctab->cvnum) ctab = &cfg.cacheex_nopushafter_tab; } else { return; } size += (ctab->cvnum * 4 + 1); if(size < 32) size = 32; // bitfield i2b_buf(2, feature, payload + i); i += 2; // payload-size if((ctab->cvnum * 4 + 1) > (int)sizeof(payload)) { cs_log_dbg(D_CACHEEX, "ERROR: to much no push after caidtvalueab-entries (max. 255)"); return; } i2b_buf(2, (ctab->cvnum * 4 + 1), payload + i); // n * (caid2+value2) + cvnum i += 2; // set payload if(ctab->cvnum > 255) { cs_log_dbg(D_CACHEEX, "ERROR: to much no push after caidtvalueab-entries (max. 255)"); return; } payload[i] = ctab->cvnum; i += 1; for(j = 0; j < ctab->cvnum; j++) { CAIDVALUETAB_DATA *d = &ctab->cvdata[j]; if(d->caid) { i2b_buf(2, d->caid, payload + i); i += 2; i2b_buf(2, d->value, payload + i); i += 2; } else { continue; } } break; // maxhop case 16: size += 2; if(size < 32) size = 32; // bitfield i2b_buf(2, feature, payload + i); i += 2; // payload-size i2b_buf(2, 2, payload + i); i += 2; // set payload if(mode == 2) { if(cl->reader->cacheex.maxhop) payload[i] = cl->reader->cacheex.maxhop; else payload[i] = 0; i += 1; if(cl->reader->cacheex.maxhop_lg) payload[i] = cl->reader->cacheex.maxhop_lg; else payload[i] = 0; } else if(mode == 3) { if(cl->account->cacheex.maxhop) payload[i] = cl->account->cacheex.maxhop; else payload[i] = 0; i += 1; if(cl->account->cacheex.maxhop_lg) payload[i] = cl->account->cacheex.maxhop_lg; else payload[i] = 0; } break; // aio-version case 32: ; size += CS_AIO_VERSION_LEN; if(size < 32) size = 32; uint8_t token[CS_AIO_VERSION_LEN]; memset(token, 0, sizeof(token)); // bitfield i2b_buf(2, feature, payload + i); i += 2; // payload-size i2b_buf(2, sizeof(token), payload + i); i += 2; // set payload snprintf((char *)token, sizeof(token), "%s", CS_AIO_VERSION); uint8_t *ofs = payload + i; memcpy(ofs, token, sizeof(token)); break; // lg_only_tab case 64: ; // bitfield i2b_buf(2, feature, payload + i); i += 2; if(mode == 2) { lgonly_tab = &cl->reader->cacheex.lg_only_in_tab; if(!lgonly_tab->nfilts) lgonly_tab = &cfg.cacheex_lg_only_in_tab; } else if(mode == 3) { lgonly_tab = &cl->account->cacheex.lg_only_in_tab; if(!lgonly_tab->nfilts) lgonly_tab = &cfg.cacheex_lg_only_in_tab; } else { return; } char *cx_aio_ftab; cx_aio_ftab = cxaio_ftab_to_buf(lgonly_tab); if(cs_strlen(cx_aio_ftab) > 0 && cx_aio_ftab[0] != '\0') { size += cs_strlen(cx_aio_ftab) * sizeof(char); // payload-size i2b_buf(2, cs_strlen(cx_aio_ftab), payload + i); i += 2; // filter counter payload[i] = lgonly_tab->nfilts; i += 1; for(j=0; j> 8; uint8_t *ofs = buf + 20; memcpy(ofs, payload, size - 20); camd35_send_without_timeout(cl, buf, size-20); //send adds +20 } void camd35_cacheex_feature_request_save(struct s_client *cl, uint8_t *buf) { int32_t field = b2i(2, (buf+20)); if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) { cl->account->cacheex.feature_bitfield = field; // flag 32 => aio-version if(cl->account->cacheex.feature_bitfield & 32) { camd35_cacheex_feature_trigger(cl, 32, 2); } } if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) { cl->reader->cacheex.feature_bitfield = field; // flag 32 => aio-version if(cl->reader->cacheex.feature_bitfield & 32) { camd35_cacheex_feature_trigger(cl, 32, 3); } } if(cl->typ == 'c' && cl->account->cacheex.mode == 3) { struct s_auth *acc = cl->account; if(acc) { acc->cacheex.feature_bitfield = field; // process feature-specific actions based on feature_bitfield received // flag 1 => set localgenerated only flag if(acc->cacheex.feature_bitfield & 1) { camd35_cacheex_feature_trigger(cl, 1, 3); } // flag 2 => set localgenerated only caids flag if(acc->cacheex.feature_bitfield & 2 && !(acc->cacheex.feature_bitfield & 64)) { camd35_cacheex_feature_trigger(cl, 2, 3); } // flag 4 => set cacheex_ecm_filter (extended) if(acc->cacheex.feature_bitfield & 4) { camd35_cacheex_feature_trigger(cl, 4, 3); } // flag 8 => np push after caids if(acc->cacheex.feature_bitfield & 8) { camd35_cacheex_feature_trigger(cl, 8, 3); } // flag 16 => maxhop if(acc->cacheex.feature_bitfield & 16) { camd35_cacheex_feature_trigger(cl, 16, 3); } // flag 32 => aio-version if(acc->cacheex.feature_bitfield & 32) { camd35_cacheex_feature_trigger(cl, 32, 3); } // flag 64 => lg_only_tab if(acc->cacheex.feature_bitfield & 64) { camd35_cacheex_feature_trigger(cl, 64, 3); } } else { cs_log_dbg(D_CACHEEX, "feature_bitfield save failed - cl, %s", username(cl)); } } else if(cl->typ == 'p' && (cl->reader->cacheex.mode == 2 || cl->reader->cacheex.mode == 1)) { struct s_reader *rdr = cl->reader; if(rdr) { rdr->cacheex.feature_bitfield = field; // process feature-specific actions // flag 1 => set localgenerated_only; cause of rdr->cacheex.localgenerated_only_in is set if(rdr->cacheex.feature_bitfield & 1) { camd35_cacheex_feature_trigger(cl, 1, 2); } // flag 2 => set lg_only_tab; cause of rdr->cacheex.lg_only_in_tab is set if(rdr->cacheex.feature_bitfield & 2 && !(rdr->cacheex.feature_bitfield & 64)) { camd35_cacheex_feature_trigger(cl, 2, 2); } // // flag 4 => set cacheex_ecm_filter (extended) if(rdr->cacheex.feature_bitfield & 4) { camd35_cacheex_feature_trigger(cl, 4, 2); } // flag 8 => no push after caids if(rdr->cacheex.feature_bitfield & 8) { camd35_cacheex_feature_trigger(cl, 8, 2); } // flag 16 => maxhop if(rdr->cacheex.feature_bitfield & 16) { camd35_cacheex_feature_trigger(cl, 16, 2); } // flag 32 => aio-version if(rdr->cacheex.feature_bitfield & 32) { camd35_cacheex_feature_trigger(cl, 32, 2); } // flag 64 => lg_only_tab if(rdr->cacheex.feature_bitfield & 64) { camd35_cacheex_feature_trigger(cl, 64, 2); } } else { cs_log_dbg(D_CACHEEX, "feature_bitfield save failed - rdr, %s", username(cl)); } } } void camd35_cacheex_feature_request(struct s_client *cl) { int i = 20; uint8_t buf[32]; memset(buf, 0, sizeof(buf)); buf[0] = 0x40; buf[1] = 12; buf[2] = 0; i2b_buf(2, CACHEEX_FEATURES, buf + i); // set feature-list here camd35_send_without_timeout(cl, buf, 12); //send adds +20 } void camd35_cacheex_feature_request_reply(struct s_client *cl, uint8_t *buf) { camd35_cacheex_feature_request_save(cl, buf); int i = 20; uint8_t rbuf[32]; memset(rbuf, 0, sizeof(rbuf)); rbuf[0] = 0x41; rbuf[1] = 12; rbuf[2] = 0; i2b_buf(2, CACHEEX_FEATURES, rbuf + i); camd35_send_without_timeout(cl, rbuf, 12); //send adds +20 } #endif /** * send push filter */ void camd35_cacheex_send_push_filter(struct s_client *cl, uint8_t mode) { struct s_reader *rdr = cl->reader; int i = 20, j; CECSPVALUETAB *filter; //maximum size: 20+255 uint8_t buf[20+242]; memset(buf, 0, sizeof(buf)); buf[0] = 0x3c; buf[1] = 0xf2; //mode==2 send filters from rdr if(mode == 2 && rdr) { filter = &rdr->cacheex.filter_caidtab; #ifdef CS_CACHEEX_AIO // if not set, use global settings if(rdr->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0) filter = &cfg.cacheex_filter_caidtab; #endif } //mode==3 send filters from acc else if(mode == 3 && cl->typ == 'c' && cl->account) { filter = &cl->account->cacheex.filter_caidtab; #ifdef CS_CACHEEX_AIO // if not set, use global settings if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0) filter = &cfg.cacheex_filter_caidtab; #endif } else { return; } i2b_buf(2, filter->cevnum, buf + i); i += 2; int32_t max_filters = 15; for(j=0; jcevnum > j){ CECSPVALUETAB_DATA *d = &filter->cevdata[j]; i2b_buf(4, d->caid, buf + i); } i += 4; } for(j=0; jcevnum > j){ CECSPVALUETAB_DATA *d = &filter->cevdata[j]; i2b_buf(4, d->cmask, buf + i); } i += 4; } for(j=0; jcevnum > j){ CECSPVALUETAB_DATA *d = &filter->cevdata[j]; i2b_buf(4, d->prid, buf + i); } i += 4; } for(j=0; jcevnum > j){ CECSPVALUETAB_DATA *d = &filter->cevdata[j]; i2b_buf(4, d->srvid, buf + i); } i += 4; } cs_log_dbg(D_CACHEEX, "cacheex: sending push filter request to %s", username(cl)); camd35_send_without_timeout(cl, buf, 242); //send adds +20 } /** * store received push filter */ static void camd35_cacheex_push_filter(struct s_client *cl, uint8_t *buf, uint8_t mode) { struct s_reader *rdr = cl->reader; int i = 20, j; int32_t caid, cmask, provid, srvid; CECSPVALUETAB *filter; //mode==2 write filters to acc if(mode == 2 && cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 2 && cl->account->cacheex.allow_filter == 1) { filter = &cl->account->cacheex.filter_caidtab; } //mode==3 write filters to rdr else if(mode == 3 && rdr && rdr->cacheex.allow_filter == 1) { filter = &rdr->cacheex.filter_caidtab; } else { return; } cecspvaluetab_clear(filter); i += 2; int32_t max_filters = 15; for(j=0; j 0){ CECSPVALUETAB_DATA d; memset(&d, 0, sizeof(d)); d.caid = b2i(4, buf + i); cecspvaluetab_add(filter, &d); } i += 4; } for(j=0; jcevnum){ CECSPVALUETAB_DATA *d = &filter->cevdata[j]; d->cmask = cmask; } i += 4; } for(j=0; jcevnum){ CECSPVALUETAB_DATA *d = &filter->cevdata[j]; d->prid = provid; } i += 4; } for(j=0; jcevnum){ CECSPVALUETAB_DATA *d = &filter->cevdata[j]; d->srvid = srvid; } i += 4; } cs_log_dbg(D_CACHEEX, "cacheex: received push filter request from %s", username(cl)); } static int32_t camd35_cacheex_push_chk(struct s_client *cl, ECM_REQUEST *er) { if( ll_count(er->csp_lastnodes) >= cacheex_maxhop(cl) // check max 10 nodes to push #ifdef CS_CACHEEX_AIO && (!er->localgenerated || (er->localgenerated && (ll_count(er->csp_lastnodes) >= cacheex_maxhop_lg(cl)))) // check maxhop_lg if cw is lg-flagged #endif ) { #ifdef CS_CACHEEX_AIO cs_log_dbg(D_CACHEEX, "cacheex: nodelist reached %d nodes(non-lg) or reached %d nodes(lg), no push", cacheex_maxhop(cl), cacheex_maxhop_lg(cl)); #else cs_log_dbg(D_CACHEEX, "cacheex: nodelist reached %d nodes, no push", cacheex_maxhop(cl)); #endif return 0; } if(cl->reader) { if(!cl->reader->tcp_connected) { cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl)); return 0; } } //if(chk_is_null_nodeid(remote_node)){ if(!cl->ncd_skey[8]) { cs_log_dbg(D_CACHEEX, "cacheex: NO peer_node_id got yet, skip!"); return 0; } uint8_t *remote_node = cl->ncd_skey; //it is sended by reader(mode 2) or client (mode 3) each 30s using keepalive msgs //search existing peer nodes: LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0); uint8_t *node; while((node = ll_li_next(li))) { cs_log_dbg(D_CACHEEX, "cacheex: check node %" PRIu64 "X == %" PRIu64 "X ?", cacheex_node_id(node), cacheex_node_id(remote_node)); if(memcmp(node, remote_node, 8) == 0) { break; } } ll_li_destroy(li); //node found, so we got it from there, do not push: if(node) { cs_log_dbg(D_CACHEEX, "cacheex: node %" PRIu64 "X found in list => skip push!", cacheex_node_id(node)); return 0; } //check if cw is already pushed if(check_is_pushed(er->cw_cache, cl)) { return 0; } cs_log_dbg(D_CACHEEX, "cacheex: push ok %" PRIu64 "X to %" PRIu64 "X %s", cacheex_node_id(camd35_node_id), cacheex_node_id(remote_node), username(cl)); return 1; } static int32_t camd35_cacheex_push_out(struct s_client *cl, struct ecm_request_t *er) { int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc; if(rc != E_FOUND && rc != E_UNHANDLED) { return -1; } //Maybe later we could support other rcs //E_FOUND : we have the CW, //E_UNHANDLED : incoming ECM request if(cl->reader) { if(!camd35_tcp_connect(cl)) { cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl)); return (-1); } } uint32_t size = sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw) + sizeof(uint8_t) + #ifdef CS_CACHEEX_AIO (ll_count(er->csp_lastnodes) + 1) * 8 + sizeof(uint8_t); #else (ll_count(er->csp_lastnodes) + 1) * 8; #endif uint8_t *buf; if(!cs_malloc(&buf, size + 20)) //camd35_send() adds +20 { return -1; } buf[0] = 0x3f; //New Command: Cache-push buf[1] = size & 0xff; buf[2] = size >> 8; buf[3] = rc; i2b_buf(2, er->srvid, buf + 8); i2b_buf(2, er->caid, buf + 10); i2b_buf(4, er->prid, buf + 12); //i2b_buf(2, er->idx, buf + 16); // Not relevant...? if(er->cwc_cycletime && er->cwc_next_cw_cycle < 2) { buf[18] = er->cwc_cycletime; // contains cwc stage3 cycletime if(er->cwc_next_cw_cycle == 1) { buf[18] = (buf[18] | 0x80); } // set bit 8 to high if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) { cl->account->cwc_info++; } else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) { cl->cwc_info++; } cs_log_dbg(D_CWC, "CWC (CE) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); } buf[19] = er->ecm[0] != 0x80 && er->ecm[0] != 0x81 ? 0 : er->ecm[0]; uint8_t *ofs = buf + 20; //write oscam ecmd5: memcpy(ofs, er->ecmd5, sizeof(er->ecmd5)); //16 ofs += sizeof(er->ecmd5); //write csp hashcode: i2b_buf(4, CSP_HASH_SWAP(er->csp_hash), ofs); ofs += 4; //write cw: memcpy(ofs, er->cw, sizeof(er->cw)); //16 ofs += sizeof(er->cw); //write node count: *ofs = ll_count(er->csp_lastnodes) + 1; ofs++; //write own node: memcpy(ofs, camd35_node_id, 8); ofs += 8; //write other nodes: LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0); uint8_t *node; while((node = ll_li_next(li))) { memcpy(ofs, node, 8); ofs += 8; } ll_li_destroy(li); #ifdef CS_CACHEEX_AIO // add localgenerated cw-flag if(er->localgenerated) { *ofs = 1; } else { *ofs = 0xFF; } #endif int32_t res = camd35_send(cl, buf, size); NULLFREE(buf); return res; } static void camd35_cacheex_push_in(struct s_client *cl, uint8_t *buf) { int8_t rc = buf[3]; if(rc != E_FOUND && rc != E_UNHANDLED) //Maybe later we could support other rcs { return; } ECM_REQUEST *er; uint16_t size = buf[1] | (buf[2] << 8); if(size < sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) { cs_log_dbg(D_CACHEEX, "cacheex: %s received old cache-push format! data ignored!", username(cl)); return; } if(!(er = get_ecmtask())) { return; } er->srvid = b2i(2, buf + 8); er->caid = b2i(2, buf + 10); er->prid = b2i(4, buf + 12); er->pid = b2i(2, buf + 16); er->ecm[0] = buf[19]!=0x80 && buf[19]!=0x81 ? 0 : buf[19]; //odd/even byte, usefull to send it over CSP and to check cw for swapping er->rc = rc; er->ecmlen = 0; if(buf[18]) { if(buf[18] & (0x01 << 7)) { er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime er->cwc_next_cw_cycle = 1; } else { er->cwc_cycletime = buf[18]; er->cwc_next_cw_cycle = 0; } } uint8_t *ofs = buf + 20; //Read ecmd5 memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); //16 ofs += sizeof(er->ecmd5); if(!check_cacheex_filter(cl, er)) { return; } #ifdef CS_CACHEEX_AIO // check incoming cache if(check_client(cl) && cl->typ == 'p' && cl->reader && cl->reader->cacheex.mode == 2 && ( (cl->reader->cacheex.filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cl->reader->cacheex.filter_caidtab)) // reader cacheex_ecm_filter not matching if set || (cl->reader->cacheex.filter_caidtab.cevnum == 0 && (cl->reader->cacheex.feature_bitfield & 4) && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab_aio)) // global cacheex_ecm_filter_aio not matching if set || (cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab)) // global cacheex_ecm_filter not matching if set ) ) { cs_log_dbg(D_CACHEEX, "cacheex: received cache not matching cacheex_ecm_filter => pushing filter again"); camd35_cacheex_send_push_filter(cl, 2); // get cache != cacheex_ecm_filter, send filter again - remote restarted if(cl->reader->cacheex.feature_bitfield & 4) camd35_cacheex_feature_trigger(cl, 4, 2); free_push_in_ecm(er); return; } if(check_client(cl) && cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3 && ( (cl->account->cacheex.filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cl->account->cacheex.filter_caidtab)) // account cacheex_ecm_filter not matching if set || (cl->account->cacheex.filter_caidtab.cevnum == 0 && (cl->account->cacheex.feature_bitfield & 4) && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab_aio)) // global cacheex_ecm_filter_aio not matching if set || (cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab)) // global cacheex_ecm_filter not matching if set ) ) { cs_log_dbg(D_CACHEEX, "cacheex: received cache not matching cacheex_ecm_filter => pushing filter again"); camd35_cacheex_send_push_filter(cl, 3); // get cache != cacheex_ecm_filter, send filter again - remote restarted if(cl->account->cacheex.feature_bitfield & 4) camd35_cacheex_feature_trigger(cl, 4, 3); free_push_in_ecm(er); return; } #endif //Read csp_hash: er->csp_hash = CSP_HASH_SWAP(b2i(4, ofs)); ofs += 4; //Read cw: memcpy(er->cw, ofs, sizeof(er->cw)); //16 ofs += sizeof(er->cw); //Check auf neues Format: uint8_t *data; if(size > (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw))) { //Read lastnodes: uint8_t count = *ofs; ofs++; #ifndef CS_CACHEEX_AIO //check max nodes: if(count > cacheex_maxhop(cl)) { cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s", (int32_t)count, cacheex_maxhop(cl), username(cl)); NULLFREE(er); return; } #endif cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl)); if (er){ er->csp_lastnodes = ll_create("csp_lastnodes"); } while(count) { if(!cs_malloc(&data, 8)) { break; } memcpy(data, ofs, 8); ofs += 8; ll_append(er->csp_lastnodes, data); count--; cs_log_dbg(D_CACHEEX, "cacheex: received node %" PRIu64 "X %s", cacheex_node_id(data), username(cl)); } #ifdef CS_CACHEEX_AIO // check byte after nodelist for "localgenerated CW"-flag if(b2i(1, ofs) == 1) { er->localgenerated = 1; cs_log_dbg(D_CACHEEX, "cacheex: received ECM with localgenerated flag %04X@%06X:%04X %s", er->caid, er->prid, er->srvid, username(cl)); //check max nodes for lg flagged cw: if(ll_count(er->csp_lastnodes) > cacheex_maxhop_lg(cl)) { cs_log_dbg(D_CACHEEX, "cacheex: received (lg) %d nodes (max=%d), ignored! %s", ll_count(er->csp_lastnodes), cacheex_maxhop_lg(cl), username(cl)); free_push_in_ecm(er); return; } } // without localgenerated flag else { //check max nodes: if(ll_count(er->csp_lastnodes) > cacheex_maxhop(cl)) { cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s", ll_count(er->csp_lastnodes), cacheex_maxhop(cl), username(cl)); free_push_in_ecm(er); return; } if( (cl->typ == 'p' && cl->reader && cl->reader->cacheex.mode == 2 && !chk_srvid_localgenerated_only_exception(er) // cx1&2 && ( // !aio (cl->cacheex_aio_checked && !cl->reader->cacheex.feature_bitfield && ( !cfg.cacheex_lg_only_in_aio_only && !cl->reader->cacheex.lg_only_in_aio_only && (cfg.cacheex_localgenerated_only_in || cl->reader->cacheex.localgenerated_only_in || chk_lg_only(er, &cl->reader->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab)) ) ) || // aio (cl->cacheex_aio_checked && cl->reader->cacheex.feature_bitfield && ( cfg.cacheex_localgenerated_only_in || cl->reader->cacheex.localgenerated_only_in || chk_lg_only(er, &cl->reader->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab) ) ) ) ) || (cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3 && !chk_srvid_localgenerated_only_exception(er) // cx3 && ( // !aio (cl->cacheex_aio_checked && !cl->account->cacheex.feature_bitfield && ( !cfg.cacheex_lg_only_in_aio_only && !cl->account->cacheex.lg_only_in_aio_only && (cfg.cacheex_localgenerated_only_in || cl->account->cacheex.localgenerated_only_in || chk_lg_only(er, &cl->account->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab)) ) ) || // aio (cl->cacheex_aio_checked && cl->account->cacheex.feature_bitfield && ( cfg.cacheex_localgenerated_only_in || cl->account->cacheex.localgenerated_only_in || chk_lg_only(er, &cl->account->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab) ) ) ) ) ) { cs_log_dbg(D_CACHEEX, "cacheex: drop ECM without localgenerated flag %04X@%06X:%04X %s", er->caid, er->prid, er->srvid, username(cl)); free_push_in_ecm(er); return; } } #endif } else { cs_log_dbg(D_CACHEEX, "cacheex: received old cachex from %s", username(cl)); er->csp_lastnodes = ll_create("csp_lastnodes"); } //store remote node id if we got one. The remote node is the first node in the node list data = ll_has_elements(er->csp_lastnodes); if(data && !cl->ncd_skey[8]) //Ok, this is tricky, we use newcamd key storage for saving the remote node { memcpy(cl->ncd_skey, data, 8); cl->ncd_skey[8] = 1; //Mark as valid node } cs_log_dbg(D_CACHEEX, "cacheex: received cacheex from remote node id %" PRIu64 "X", cacheex_node_id(cl->ncd_skey)); //for compatibility: add peer node if no node received (not working now, maybe later): if(!ll_count(er->csp_lastnodes) && cl->ncd_skey[8]) { if(!cs_malloc(&data, 8)) { #ifdef CS_CACHEEX_AIO free_push_in_ecm(er); #endif return; } memcpy(data, cl->ncd_skey, 8); ll_append(er->csp_lastnodes, data); cs_log_dbg(D_CACHEEX, "cacheex: added missing remote node id %" PRIu64 "X", cacheex_node_id(data)); } #ifdef CS_CACHEEX_AIO if (er->cwc_cycletime && er->cwc_next_cw_cycle < 2) { if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) { cl->account->cwc_info++; } else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) { cl->cwc_info++; } cs_log_dbg(D_CWC, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); } #endif cacheex_add_to_cache(cl, er); } void camd35_cacheex_recv_ce1_cwc_info(struct s_client *cl, uint8_t *buf, int32_t idx) { if(!(buf[0] == 0x01 && buf[18] < 0xFF && buf[18] > 0x00)) // cwc info ; normal camd3 ecms send 0xFF but we need no cycletime of 255 ;) return; ECM_REQUEST *er = NULL; int32_t i; for(i = 0; i < cfg.max_pending; i++) { if (cl->ecmtask[i].idx == idx) { er = &cl->ecmtask[i]; break; } } if(!er) { return; } int8_t rc = buf[3]; if(rc != E_FOUND) { return; } if(buf[18]) { if(buf[18] & (0x01 << 7)) { er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime er->parent->cwc_cycletime = er->cwc_cycletime; er->cwc_next_cw_cycle = 1; er->parent->cwc_next_cw_cycle = er->cwc_next_cw_cycle; } else { er->cwc_cycletime = buf[18]; er->parent->cwc_cycletime = er->cwc_cycletime; er->cwc_next_cw_cycle = 0; er->parent->cwc_next_cw_cycle = er->cwc_next_cw_cycle; } } if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) { cl->account->cwc_info++; } else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) { cl->cwc_info++; } cs_log_dbg(D_CWC, "CWC (CE1) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); } /** * when a server client connects */ static void camd35_server_client_init(struct s_client *cl) { if(!cl->init_done) { cl->cacheex_needfilter = 1; } } /** * store received remote id */ static void camd35_cacheex_push_receive_remote_id(struct s_client *cl, uint8_t *buf) { memcpy(cl->ncd_skey, buf + 20, 8); cl->ncd_skey[8] = 1; cs_log_dbg(D_CACHEEX, "cacheex: received id answer from %s: %" PRIu64 "X", username(cl), cacheex_node_id(cl->ncd_skey)); } void camd35_cacheex_init_dcw(struct s_client *client, ECM_REQUEST *er) { uint8_t *buf = er->src_data; // get orig request if(((client->typ == 'c' && client->account && client->account->cacheex.mode) || ((client->typ == 'p' || client->typ == 'r') && (client->reader && client->reader->cacheex.mode))) && er->cwc_cycletime && er->cwc_next_cw_cycle < 2) // ce1 { buf[18] = er->cwc_cycletime; // contains cwc stage3 cycletime if(er->cwc_next_cw_cycle == 1) { buf[18] = (buf[18] | 0x80); } // set bit 8 to high if(client->typ == 'c' && client->account && client->account->cacheex.mode) { client->account->cwc_info++; } else if((client->typ == 'p' || client->typ == 'r') && (client->reader && client->reader->cacheex.mode)) { client->cwc_info++; } cs_log_dbg(D_CWC, "CWC (CE1) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(client), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); buf[19] = er->ecm[0]; } } /** * send own id */ void camd35_cacheex_push_send_own_id(struct s_client *cl, uint8_t *mbuf) { uint8_t rbuf[32]; //minimal size if(!cl->crypted) { return; } cs_log_dbg(D_CACHEEX, "cacheex: received id request from node %" PRIu64 "X %s", cacheex_node_id(mbuf + 20), username(cl)); memset(rbuf, 0, sizeof(rbuf)); rbuf[0] = 0x3e; rbuf[1] = 12; rbuf[2] = 0; memcpy(rbuf + 20, camd35_node_id, 8); cs_log_dbg(D_CACHEEX, "cacheex: sending own id %" PRIu64 "X request %s", cacheex_node_id(camd35_node_id), username(cl)); camd35_send(cl, rbuf, 12); //send adds +20 } bool camd35_cacheex_server(struct s_client *client, uint8_t *mbuf) { switch(mbuf[0]) { case 0x3c: // Cache-push filter request if(client->account && client->account->cacheex.mode==2){ camd35_cacheex_push_filter(client, mbuf, 2); } break; case 0x3d: // Cache-push id request camd35_cacheex_push_receive_remote_id(client, mbuf); //reader send request id with its nodeid, so we save it! camd35_cacheex_push_send_own_id(client, mbuf); if(client->cacheex_needfilter && client->account && client->account->cacheex.mode==3){ camd35_cacheex_send_push_filter(client, 3); client->cacheex_needfilter = 0; } #ifdef CS_CACHEEX_AIO if(!client->cacheex_aio_checked && ((client->account && client->account->cacheex.mode > 0) || (client->reader && client->reader->cacheex.mode > 0))) { camd35_cacheex_feature_request(client); client->cacheex_aio_checked = 1; } #endif break; case 0x3e: // Cache-push id answer camd35_cacheex_push_receive_remote_id(client, mbuf); break; case 0x3f: // Cache-push camd35_cacheex_push_in(client, mbuf); break; #ifdef CS_CACHEEX_AIO case 0x40: // cacheex-features request camd35_cacheex_feature_request_reply(client, mbuf); break; case 0x41: // cacheex-features answer // camd35_cacheex_feature_request_save(client, mbuf); break; case 0x42: // cacheex-feature trigger in camd35_cacheex_feature_trigger_in(client, mbuf); break; #endif default: return 0; // Not processed by cacheex } return 1; // Processed by cacheex } bool camd35_cacheex_recv_chk(struct s_client *client, uint8_t *buf) { struct s_reader *rdr = client->reader; switch(buf[0]) { case 0x3c: // Cache-push filter request if(rdr->cacheex.mode==3){ camd35_cacheex_push_filter(client, buf, 3); } break; case 0x3d: // Cache-push id request camd35_cacheex_push_receive_remote_id(client, buf); //client send request id with its nodeid, so we save it! camd35_cacheex_push_send_own_id(client, buf); break; case 0x3e: // Cache-push id answer camd35_cacheex_push_receive_remote_id(client, buf); #ifdef CS_CACHEEX_AIO if(!client->cacheex_aio_checked && ((client->account && client->account->cacheex.mode > 0) || (client->reader && client->reader->cacheex.mode > 0))) { camd35_cacheex_feature_request(client); client->cacheex_aio_checked = 1; } #endif break; case 0x3f: //cache-push camd35_cacheex_push_in(client, buf); break; #ifdef CS_CACHEEX_AIO case 0x40: // cacheex-features request camd35_cacheex_feature_request_reply(client, buf); break; case 0x41: // cacheex-features answer // camd35_cacheex_feature_request_save(client, buf); break; case 0x42: // cacheex-feature trigger in camd35_cacheex_feature_trigger_in(client, buf); break; #endif default: return 0; // Not processed by cacheex } return 1; // Processed by cacheex } /** * request remote id */ void camd35_cacheex_push_request_remote_id(struct s_client *cl) { uint8_t rbuf[32];//minimal size memset(rbuf, 0, sizeof(rbuf)); rbuf[0] = 0x3d; rbuf[1] = 12; rbuf[2] = 0; memcpy(rbuf + 20, camd35_node_id, 8); cs_log_dbg(D_CACHEEX, "cacheex: sending id request to %s", username(cl)); camd35_send(cl, rbuf, 12); //send adds +20 } void camd35_cacheex_module_init(struct s_module *ph) { ph->c_cache_push = camd35_cacheex_push_out; ph->c_cache_push_chk = camd35_cacheex_push_chk; ph->s_init = camd35_server_client_init; } #endif