Changeset 8432


Ignore:
Timestamp:
02/26/13 21:38:45 (9 years ago)
Author:
theparasol
Message:
  • Added optional ecm unique check to ratelimiter (experimental)
Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/globals.h

    r8425 r8432  
    11021102    uint16_t        srvid;
    11031103    time_t          last;
     1104    uchar           ecmd5[CS_ECMSTORESIZE];
     1105   
    11041106};
    11051107#define MAXECMRATELIMIT 20
     
    13621364    int32_t         ratelimitecm;
    13631365    int32_t         ratelimitseconds;
     1366    int8_t          ecmunique; // check for matching ecm hash in ratelimitslot 
    13641367    time_t          lastdvbapirateoverride;
    13651368    uint32_t        ecmsok;
  • trunk/module-webif.c

    r8426 r8432  
    14251425        tpl_printf(vars, TPLADD, "RATELIMITECM", "%d", rdr->ratelimitecm);
    14261426        tpl_printf(vars, TPLADD, "RATELIMITSECONDS", "%d", rdr->ratelimitseconds);
     1427        // ECMUNIQUE
     1428        if(!apicall) {
     1429            tpl_addVar(vars, TPLADD, "ECMUNIQUECHECKED", (rdr->ecmunique == 1) ? "checked" : "");
     1430        } else {
     1431            tpl_addVar(vars, TPLADD, "ECMUNIQUE", (rdr->ecmunique == 1) ? "1" : "0");
     1432        }
    14271433    }
    14281434    // Cooldown
  • trunk/oscam-chk.c

    r8370 r8432  
    1111
    1212#ifdef WITH_CARDREADER
    13 static int32_t ecm_ratelimit_findspace(struct s_reader *reader, ECM_REQUEST *er, int32_t maxloop)
    14 {
    15     int32_t h, foundspace;
     13static int32_t ecm_ratelimit_findspace(struct s_reader * reader, ECM_REQUEST *er, int32_t maxloop, int32_t reader_mode)
     14{
     15    int32_t h, foundspace = -1;
    1616    time_t actualtime = time(NULL);
    17 
    18     for (h = 0; h < maxloop; h++) {
    19         // Check for a useable slot
    20         if ((actualtime - reader->rlecmh[h].last > reader->ratelimitseconds) ||
    21         reader->rlecmh[h].last == -1 || reader->rlecmh[h].srvid == er->srvid) {
    22             if (h < maxloop - 1) { // Do housekeeping
    23                 for (foundspace = h + 1; foundspace < maxloop; foundspace++) {
    24                     // Check if srvid is not already in a slot
    25                     if (reader->rlecmh[foundspace].srvid == er->srvid) {
    26                         // Just moving and freeing slot no new assignment
    27                         reader->rlecmh[h].srvid = reader->rlecmh[foundspace].srvid;
    28                         reader->rlecmh[h].last = reader->rlecmh[foundspace].last;
    29                         reader->rlecmh[foundspace].srvid = -1;
    30                         reader->rlecmh[foundspace].last = -1;
    31                         cs_debug_mask(D_TRACE,
    32                         "ratelimiter moving srvid %04X from slot #%d/%d to #%d/%d of reader %s",
    33                         er->srvid, foundspace + 1, maxloop, h + 1, maxloop, reader->label);
     17    for (h = 0; h < maxloop; h++) { // always release slots with srvid that are overtime, even if not called from reader module to maximize available slots!
     18        if ((actualtime - reader->rlecmh[h].last >= reader->ratelimitseconds) && (reader->rlecmh[h].last !=-1)){
     19            cs_debug_mask(D_TRACE, "ratelimiter old srvid %04X released from slot #%d/%d of reader %s (%d>=%d ratelimitsec!)", reader->rlecmh[h].srvid, h+1, maxloop, reader->label, (int) (actualtime - reader->rlecmh[h].last), reader->ratelimitseconds);
     20            reader->rlecmh[h].last = -1;
     21            reader->rlecmh[h].srvid = -1;
     22        }
     23    }
     24   
     25    for (h = 0; h < maxloop; h++) { // check if srvid is already in a slot
     26        if (reader->rlecmh[h].srvid == er->srvid) {
     27            cs_debug_mask(D_TRACE, "ratelimiter found srvid %04X for %d sec in slot #%d/%d of reader %s",er->srvid, (int) (actualtime - reader->rlecmh[h].last), h+1, maxloop,reader->label);
     28           
     29            if(reader_mode && reader->ecmunique){ // allow just 1 ecm in a slot instead of a srvid
     30                if (memcmp(reader->rlecmh[h].ecmd5, er->ecmd5, CS_ECMSTORESIZE)){
     31                    char ecmd5[17*3];
     32                    cs_hexdump(0, reader->rlecmh[h].ecmd5, 16, ecmd5, sizeof(ecmd5));
     33                    cs_debug_mask(D_TRACE, "ratelimiter ecm %s in this slot for next %d seconds -> skipping this slot!", ecmd5, (int)
     34                        (reader->ratelimitseconds - (actualtime - reader->rlecmh[h].last)));
     35                    continue;
     36                }
     37            }
     38            if (h > 0){
     39                for (foundspace = 0; foundspace < h; foundspace++) { // check for free lower slot
     40                    if (reader->rlecmh[foundspace].last ==- 1) {                               
     41                        reader->rlecmh[h].srvid = -1;
     42                        reader->rlecmh[h].last = -1;
     43                        cs_debug_mask(D_TRACE, "ratelimiter moving srvid %04X to slot #%d/%d of reader %s",er->srvid, foundspace+1, maxloop, reader->label);
     44                        return foundspace; // moving to lower free slot!
    3445                    }
    35                     // Release slots with srvid that are overtime,
    36                     // even if not called from reader module, to maximize available slots!
    37                     if ((actualtime - reader->rlecmh[foundspace].last > reader->ratelimitseconds) &&
    38                     (reader->rlecmh[foundspace].last != -1)) {
    39                         cs_debug_mask(D_TRACE,
    40                             "ratelimiter old srvid %04X released from slot #%d/%d of reader %s (%d > %d ratelimitsec!)",
    41                             reader->rlecmh[foundspace].srvid, foundspace + 1, maxloop,
    42                             reader->label, (int) (actualtime - reader->rlecmh[foundspace].last),
    43                             reader->ratelimitseconds);
    44                         reader->rlecmh[foundspace].last = -1;
    45                         reader->rlecmh[foundspace].srvid = -1;
    46                     }
    47                 } // End for
    48             } // End if
    49             // Release slots with srvid that are overtime,
    50             // even if not called from reader module, to maximize available slots!
    51             if (reader->rlecmh[h].srvid != er->srvid && reader->rlecmh[h].last != -1) {
    52                 // This h slot is found because it is overtime.
    53                 cs_debug_mask(D_TRACE,
    54                     "ratelimiter old srvid %04X released from slot #%d/%d of reader %s (%d > %d ratelimitsec!)",
    55                     reader->rlecmh[h].srvid, h + 1, maxloop,
    56                     reader->label, (int) (actualtime - reader->rlecmh[h].last),
    57                     reader->ratelimitseconds);
    58                 reader->rlecmh[h].last = -1;
    59                 reader->rlecmh[h].srvid = -1;
     46                }
    6047            }
    61             if (reader->rlecmh[h].srvid == er->srvid)
    62                 cs_debug_mask(D_TRACE, "ratelimiter found srvid %04X for %d sec in slot #%d/%d of reader %s",
    63                     er->srvid, (int) (actualtime - reader->rlecmh[h].last), h+1, maxloop, reader->label);
    64             return h; // Free slot found, possible to assign it!
    65         }
     48            return h; // Found but cant move to lower slot!
     49        }
     50    } // srvid not found in slots!
     51    if (!reader_mode) return -1; // who's calling us? reader or some stat prober?  If reader then register otherwise just report!
     52    for (h = 0; h < maxloop; h++) { // check for free slot
     53        if (reader->rlecmh[h].last ==- 1) {
     54            cs_debug_mask(D_TRACE, "ratelimiter added srvid %04X to slot #%d/%d of reader %s", er->srvid, h+1, maxloop, reader->label);
     55            return h; // free slot found -> assign it!
     56        }
     57        else cs_debug_mask(D_TRACE, "ratelimiter srvid %04X for %d seconds present in slot #%d/%d of reader %s", reader->rlecmh[h].srvid, (int) (actualtime - reader->rlecmh[h].last), h+1, maxloop, reader->label); //occupied slots
    6658    }
    6759
     
    7062    foundspace = -1;
    7163    if ((cfg.dvbapi_enabled == 1) && streq(er->client->account->usr, cfg.dvbapi_usr)) {
    72         if (reader->lastdvbapirateoverride < actualtime - reader->ratelimitseconds) {
    73             time_t minecmtime = actualtime;
     64        if ((reader->lastdvbapirateoverride) < (time(NULL) - reader->ratelimitseconds)) {
     65            time_t minecmtime = time(NULL);
    7466            for (h = 0; h < maxloop; h++) {
    7567                if(reader->rlecmh[h].last < minecmtime) {
     
    7870                }
    7971            }
    80             reader->lastdvbapirateoverride = actualtime;
    81             cs_debug_mask(D_TRACE, "prioritizing DVBAPI user %s over other watching client",
    82                 er->client->account->usr);
    83             cs_debug_mask(D_TRACE, "ratelimiter forcing srvid %04X into slot #%d/%d of reader %s",
    84                 er->srvid, foundspace + 1, maxloop, reader->label);
    85             return foundspace; // Free slot found, possible to assign it!
    86         }
    87         else cs_debug_mask(D_TRACE, "DVBAPI User %s is switching too fast for ratelimit and can't be prioritized!",
     72            reader->lastdvbapirateoverride = time(NULL);
     73            cs_debug_mask(D_TRACE, "prioritizing DVBAPI user %s over other watching client", er->client->account->usr);
     74            cs_debug_mask(D_TRACE, "ratelimiter forcing srvid %04X into slot #%d/%d of reader %s", er->srvid, foundspace+1, maxloop, reader->label);
     75            return foundspace;
     76        } else cs_debug_mask(D_TRACE, "DVBAPI User %s is switching too fast for ratelimit and can't be prioritized!",
    8877            er->client->account->usr);
    8978    }
     
    9382}
    9483
    95 static void sort_ecmrl(struct s_reader *reader)
    96 {
    97     int32_t i, j, loc;
    98     struct ecmrl tmp;
    99 
    100     for(i = 0; i < reader->ratelimitecm; i++) {
    101         loc = i;
    102         tmp = reader->rlecmh[i];
    103 
    104         for(j = i + 1; j < MAXECMRATELIMIT; j++) {
    105             if(reader->rlecmh[j].last > tmp.last) {
    106                 loc = j;
    107                 tmp = reader->rlecmh[j];
     84int32_t ecm_ratelimit_check(struct s_reader * reader, ECM_REQUEST *er, int32_t reader_mode)
     85{
     86    int32_t foundspace = 0, maxslots = MAXECMRATELIMIT; //init slots to oscam global maximums
     87
     88    if (!reader->ratelimitecm) return OK; /* no rate limit set */
     89
     90    if (reader->cooldown[0]) { // Do we use cooldown?
     91        if (reader->cooldownstate == 1) { // Cooldown in ratelimit phase
     92        maxslots = reader->ratelimitecm; // use user defined ratelimitecm
     93            if (time(NULL) - reader->cooldowntime >= reader->cooldown[1]) { // check if cooldowntime is elapsed
     94                reader->cooldownstate = 0; // set cooldown setup phase
     95                reader->cooldowntime = 0; // reset cooldowntime
     96                maxslots = MAXECMRATELIMIT; //use oscam defined max slots
     97                cs_log("Reader: %s ratelimiter returning to setup phase cooling down period of %d seconds is done!", reader->label, reader->cooldown[1]);
    10898            }
    109         } // for j
    110 
    111         if(loc != i) {
    112             reader->rlecmh[loc] = reader->rlecmh[i];
    113             reader->rlecmh[i] = tmp;
    114         }
    115     } // for i
    116 
    117     // release all slots above ratelimit ecm
    118     for (i = reader->ratelimitecm; i < MAXECMRATELIMIT; i++) {
    119         reader->rlecmh[i].last = -1;
    120         reader->rlecmh[i].srvid = -1;
    121     }
    122 
    123 }
    124 
    125 int32_t ecm_ratelimit_check(struct s_reader *reader, ECM_REQUEST *er, int32_t reader_mode)
    126 // If reader_mode is 1, ECM_REQUEST need to be assigned to reader and slot.
    127 // Else just report if a free slot is available.
    128 {
    129     int32_t foundspace = -1, h, maxslots = MAXECMRATELIMIT; //init slots to oscam global maximums
    130 
    131     // No rate limit set
    132     if (!reader->ratelimitecm) return OK;
    133 
    134     // Below this line: rate limit functionality.
    135     // No cooldown set
    136     if (!reader->cooldown[0]) {
    137         cs_debug_mask(D_TRACE, "ratelimiter find a slot for srvid %04X on reader %s reader_mode = %d",
    138             er->srvid, reader->label, reader_mode);
    139         foundspace = ecm_ratelimit_findspace(reader, er, reader->ratelimitecm);
    140         if (foundspace < 0) {
    141             if (reader_mode) {
    142                 cs_debug_mask(D_TRACE, "ratelimiter no free slot for srvid %04X on reader %s -> dropping!", er->srvid, reader->label);
    143                 write_ecm_answer(reader, er, E_NOTFOUND, E2_RATELIMIT, NULL, "Ratelimiter: no slots free!");
     99        }
     100    }
     101   
     102    if (reader_mode){
     103        char ecmd5[17*3];
     104        cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5));
     105        cs_debug_mask(D_TRACE, "ratelimiter find a slot for srvid %04X ecm %s on reader %s", er->srvid, ecmd5, reader->label);
     106    }
     107    else {
     108        cs_debug_mask(D_TRACE, "ratelimiter find a slot for srvid %04X on reader %s", er->srvid, reader->label);
     109    }
     110    foundspace = ecm_ratelimit_findspace(reader, er, maxslots, reader_mode);
     111    if (foundspace < 0 || foundspace >= reader->ratelimitecm) { /* No space due to ratelimit */
     112        if (!reader_mode) return OK; // who's calling us? reader or some stat prober?  If reader then register otherwise just report!
     113        if (reader->cooldown[0] && reader->cooldownstate == 0){ // we are in setup phase of cooldown
     114            cs_log("Reader: %s ratelimiter detected overrun ecmratelimit of %d during setup phase!",reader->label, reader->ratelimitecm);
     115            reader->cooldownstate = 2; /* Entering cooldowndelay phase */
     116            reader->cooldowntime = time(NULL); // set cooldowntime to calculate delay
     117            cs_debug_mask(D_TRACE, "ratelimiter cooldowndelaying %d seconds", reader->cooldown[0]);
     118            if (foundspace < 0) return ERROR; //not even trowing an error... obvious reason ;)
     119            reader->rlecmh[foundspace].last=time(NULL); // register new slot >ecmratelimit
     120            reader->rlecmh[foundspace].srvid=er->srvid;
     121            return OK;
     122        }
     123        if (reader->cooldown[0] && reader->cooldownstate == 2) { // check if cooldowndelay is elapsed
     124            if (time(NULL) - reader->cooldowntime <= reader->cooldown[0]) { // we are in cooldowndelay!
     125                if (foundspace < 0) return ERROR; //not even trowing an error... obvious reason ;)
     126                if (reader_mode){ // who's calling us? reader or some stat prober?  If reader then register otherwise just report!
     127                reader->rlecmh[foundspace].last=time(NULL); // register new slot >ecmratelimit
     128                reader->rlecmh[foundspace].srvid=er->srvid;
     129                if(reader_mode) memcpy(reader->rlecmh[foundspace].ecmd5, er->ecmd5, CS_ECMSTORESIZE); // register ecmhash
     130                }
     131                return OK;
    144132            }
    145             return ERROR; // not even trowing an error... obvious reason ;)
    146         }
    147         else {
    148             if (reader_mode) {
    149                 // Register new slot
    150                 reader->rlecmh[foundspace].last = time(NULL);
    151                 reader->rlecmh[foundspace].srvid = er->srvid;
     133            else {
     134                if (!reader_mode) return ERROR; //who's calling us? reader or some stat prober?  If reader then register otherwise just report!
     135                reader->cooldownstate = 1; // Entering ratelimit for cooldown ratelimitseconds
     136                reader->cooldowntime = time(NULL); // set time to enforce ecmratelimit for defined cooldowntime
     137                cs_log("Reader: %s ratelimiter starting cooling down period of %d seconds!", reader->label, reader->cooldown[1]);
     138               
     139                for (foundspace = reader->ratelimitecm; foundspace <= maxslots; foundspace++) { // release all slots above ratelimit
     140                reader->rlecmh[foundspace].last = -1;
     141                reader->rlecmh[foundspace].srvid = -1;
     142                }
    152143            }
    153             return OK;
    154         }
    155     }
    156 
    157     // Below this line: rate limit functionality with cooldown option.
    158 
    159     // Cooldown state cycle:
    160     // state = 0: Cooldown setup phase. No rate limit set.
    161     //  If number of ecm request exceed reader->ratelimitecm, cooldownstate goes to 2.
    162     // state = 2: Cooldown delay phase. No rate limit set.
    163     //  If number of ecm request still exceed reader->ratelimitecm at end of cooldown delay phase,
    164     //      cooldownstate goes to 1 (rate limit phase).
    165     //  Else return back to setup phase (state 0).
    166     // state = 1: Cooldown ratelimit phase. Rate limit set.
    167     //  If cooldowntime reader->cooldown[1] is elapsed, return to cooldown setup phase (state 0).
    168 
    169     if (reader->cooldownstate == 1) { // Cooldown in ratelimit phase
    170         if (time(NULL) - reader->cooldowntime <= reader->cooldown[1]) // check if cooldowntime is elapsed
    171             maxslots = reader->ratelimitecm; // use user defined ratelimitecm
    172         else { // Cooldown time is elapsed
    173             reader->cooldownstate = 0; // set cooldown setup phase
    174             reader->cooldowntime = 0; // reset cooldowntime
    175             maxslots = MAXECMRATELIMIT; //use oscam defined max slots
    176             cs_log("Reader: %s ratelimiter returning to setup phase cooling down period of %d seconds is done!",
    177                 reader->label, reader->cooldown[1]);
    178         }
    179     } // if cooldownstate == 1
    180 
    181     if (reader->cooldownstate == 2 && time(NULL) - reader->cooldowntime > reader->cooldown[0]) {
    182         // Need to check if the otherslots are not exceeding the ratelimit at the moment that
    183         // cooldown[0] time was exceeded!
    184         // time_t actualtime = reader->cooldowntime + reader->cooldown[0];
    185         maxslots = 0; // maxslots is used as counter
    186         for (h = 0; h < MAXECMRATELIMIT; h++) {
    187             // how many active slots are registered at end of cooldown delay period
    188             if (reader->cooldowntime + reader->cooldown[0] - reader->rlecmh[h].last
    189                 <= reader->ratelimitseconds) {
    190                 maxslots++;
    191                 if (maxslots > reader->ratelimitecm) break; // Need to go cooling down phase
     144        }
     145        // Ratelimit and cooldown in ratelimitseconds
     146        if (!reader_mode) return ERROR; //who's calling us? reader or some stat prober?  If reader then register otherwise just report!
     147        cs_debug_mask(D_TRACE, "ratelimiter no free slot for srvid %04X on reader %s -> dropping!", er->srvid, reader->label);
     148        write_ecm_answer(reader, er, E_NOTFOUND, E2_RATELIMIT, NULL, "Ratelimiter: no slots free!");
     149        return ERROR;
     150    }
     151    if (reader_mode) { //who's calling us? reader or some stat prober?  If reader then register otherwise just report!
     152        reader->rlecmh[foundspace].last=time(NULL); //we are within ecmratelimits
     153        reader->rlecmh[foundspace].srvid=er->srvid;
     154        memcpy(reader->rlecmh[foundspace].ecmd5, er->ecmd5, CS_ECMSTORESIZE);// register ecmhash
     155        }
     156    if (reader->cooldown[0] && reader->cooldownstate == 2) { // check if cooldowndelay is elapsed
     157            if (time(NULL) - reader->cooldowntime > reader->cooldown[0]) {
     158                reader->cooldownstate = 0; // return to cooldown setup phase
     159                reader->cooldowntime = 0; // reset cooldowntime
     160                maxslots = MAXECMRATELIMIT; //use oscam defined max slots
     161                cs_log("Reader: %s ratelimiter returned to setup phase after %d seconds cooldowndelay!",reader->label, reader->cooldown[0]);
    192162            }
    193         }
    194 
    195         if (maxslots <= reader->ratelimitecm) {
    196             reader->cooldownstate = 0; // set cooldown setup phase
    197             reader->cooldowntime = 0; // reset cooldowntime
    198             maxslots = MAXECMRATELIMIT; // maxslots is maxslots again
    199             cs_log("Reader: %s ratelimiter returning to setup phase after %d seconds cooldowndelay!",
    200                 reader->label, reader->cooldown[0]);
    201         }
    202         else {
    203             reader->cooldownstate = 1; // Entering ratelimit for cooldown ratelimitseconds
    204             reader->cooldowntime = time(NULL); // set time to enforce ecmratelimit for defined cooldowntime
    205             maxslots = reader->ratelimitecm; // maxslots is maxslots again
    206             sort_ecmrl(reader); // keep youngest ecm requests in list + housekeeping
    207             cs_log("Reader: %s ratelimiter starting cooling down period of %d seconds!",
    208                 reader->label, reader->cooldown[1]);
    209         }
    210     } // if cooldownstate == 2
    211 
    212     cs_debug_mask(D_TRACE, "ratelimiter cooldown find a slot for srvid %04X on reader %s reader_mode = %d",
    213         er->srvid, reader->label, reader_mode);
    214     foundspace = ecm_ratelimit_findspace(reader, er, maxslots);
    215     if (foundspace < 0) { // No space is no space, done!
    216         //who's calling us? reader or some stat prober?  If reader then register otherwise just report!
    217         if (reader_mode) {
    218             cs_debug_mask(D_TRACE, "ratelimiter no free slot for srvid %04X on reader %s -> dropping!",
    219                 er->srvid, reader->label);
    220             write_ecm_answer(reader, er, E_NOTFOUND, E2_RATELIMIT, NULL, "Ratelimiter: no slots free!");
    221         }
    222         return ERROR; // not even trowing an error... obvious reason ;)
    223     }
    224 
    225     if (reader->cooldownstate == 0 && foundspace >= reader->ratelimitecm) {
    226         if (!reader_mode) return OK; // No actual ecm request, just check
    227         cs_log("Reader: %s ratelimiter detected overrun ecmratelimit of %d during setup phase!",
    228             reader->label, reader->ratelimitecm);
    229         reader->cooldownstate = 2; // Entering cooldowndelay phase
    230         reader->cooldowntime = time(NULL); // Set cooldowntime to calculate delay
    231         cs_debug_mask(D_TRACE, "ratelimiter cooldowndelaying %d seconds", reader->cooldown[0]);
    232     }
    233 
    234     // Cooldown state housekeeping is done. There is a slot available.
    235     if (reader_mode) {
    236         // Register new slot
    237         reader->rlecmh[foundspace].last = time(NULL);
    238         reader->rlecmh[foundspace].srvid = er->srvid;
    239163    }
    240164    return OK;
  • trunk/oscam-config-reader.c

    r8361 r8432  
    793793    DEF_OPT_FUNC("ratelimitecm"         , 0,                            ratelimitecm_fn ),
    794794    DEF_OPT_FUNC("ratelimitseconds"     , 0,                            ratelimitseconds_fn ),
     795    DEF_OPT_INT8("ecmunique"            , OFS(ecmunique),               0 ),
    795796    DEF_OPT_FUNC("cooldown"             , 0,                            cooldown_fn ),
    796797    DEF_OPT_FUNC("cooldowndelay"        , 0,                            cooldowndelay_fn ),
     
    820821#endif
    821822        "deprecated", "ndsversion", "ratelimitecm", "ratelimitseconds",
    822         "cooldown",
     823        "cooldown", "ecmunique",
    823824        0
    824825    };
  • trunk/webif/readerconfig/readerconfig_hwreader.html

    r8418 r8432  
    11                <TR><TD>##TPLHELPPREFIX##server#detect##TPLHELPSUFFIX##Detect:</A></TD><TD><input name="detect" type="text" size="5" maxlength="5" value="##DETECT##"></TD></TR>
    2                 <TR><TD>##TPLHELPPREFIX##server#mhz##TPLHELPSUFFIX##Mhz:</A></TD><TD><input name="mhz" type="text" size="5" maxlength="5" value="##MHZ##"> Dreambox Mipsel: 2700, PPC: 3150</TD></TR>
     2                <TR><TD>##TPLHELPPREFIX##server#mhz##TPLHELPSUFFIX##Mhz:</A></TD><TD><input name="mhz" type="text" size="5" maxlength="5" value="##MHZ##"> Dreambox Mipsel: 2700, PPC: 3150, DM7025: 8300</TD></TR>
    33                <TR><TD>##TPLHELPPREFIX##server#cardmhz##TPLHELPSUFFIX##Cardmhz:</A></TD><TD><input name="cardmhz" type="text" size="5" maxlength="5" value="##CARDMHZ##"> Dreambox Auto Mode: -1</TD></TR>
    44##TPLREADERCONFIGRSAKEY##
     
    77##TPLREADERCONFIGNANO##
    88                <TR><TD>##TPLHELPPREFIX##server#ratelimitecm##TPLHELPSUFFIX##Ratelimit ECM:</A></TD><TD><input name="ratelimitecm" type="text" size="5" maxlength="5" value="##RATELIMITECM##"></TD></TR>
     9                <TR><TD>##TPLHELPPREFIX##server#ecmunique##TPLHELPSUFFIX##ECM Unique:</A><input name="ecmunique" type="hidden" value="0"></TD><TD><input name="ecmunique" type="checkbox" value="1" ##ECMUNIQUECHECKED##></TD></TR>
    910                <TR><TD>##TPLHELPPREFIX##server#ratelimitseconds##TPLHELPSUFFIX##Ratelimit seconds:</A></TD><TD><input name="ratelimitseconds" type="text" size="5" maxlength="5" value="##RATELIMITSECONDS##"></TD></TR>
    1011                <TR><TD>##TPLHELPPREFIX##server#cooldowndelay##TPLHELPSUFFIX##Cooldown Delay:</A></TD><TD><input name="cooldowndelay" type="text" size="5" maxlength="5" value="##COOLDOWNDELAY##"></TD></TR>
Note: See TracChangeset for help on using the changeset viewer.