static bool pcm_valid(xpd_t *xpd, xpacket_t *pack) { xpp_line_t lines = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines); int i; int count = 0; uint16_t good_len; BUG_ON(!pack); BUG_ON(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL, PCM_READ)); /* * Don't use for_each_line(xpd, i) here because for BRI it will * ignore the channels of the other xpd's in the same unit. */ for (i = 0; i < CHANNELS_PERXPD; i++) if(IS_SET(lines, i)) count++; /* FRAMES: include opcode in calculation */ good_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + count * 8; if(XPACKET_LEN(pack) != good_len) { static int rate_limit = 0; XPD_COUNTER(xpd, RECV_ERRORS)++; if((rate_limit++ % 1000) <= 10) { XPD_ERR(xpd, "BAD PCM REPLY: packet_len=%d (should be %d), count=%d\n", XPACKET_LEN(pack), good_len, count); dump_packet("BAD PCM REPLY", pack, 1); } return 0; } return 1; }
void dump_packet(const char *msg, const xpacket_t *packet, bool debug) { byte op = XPACKET_OP(packet); byte *addr = (byte *)&XPACKET_ADDR(packet); if(!debug) return; printk(KERN_DEBUG "%s: XPD=%1X-%1X%c (0x%X) OP=0x%02X LEN=%d", msg, XPACKET_ADDR_UNIT(packet), XPACKET_ADDR_SUBUNIT(packet), (XPACKET_ADDR_SYNC(packet))?'+':' ', *addr, op, XPACKET_LEN(packet)); #if VERBOSE_DEBUG { int i; byte *p = (byte *)packet; printk(" BYTES: "); for(i = 0; i < XPACKET_LEN(packet); i++) { static int limiter = 0; if(i >= sizeof(xpacket_t)) { if(limiter < ERR_REPORT_LIMIT) { ERR("%s: length overflow i=%d > sizeof(xpacket_t)=%lu\n", __FUNCTION__, i+1, (long)sizeof(xpacket_t)); } else if(limiter == ERR_REPORT_LIMIT) { ERR("%s: error packet #%d... squelsh reports.\n", __FUNCTION__, limiter); } limiter++; break; } if (debug) printk("%02X ", p[i]); } } #endif printk("\n"); }
static int xframe_receive_cmd(xbus_t *xbus, xframe_t *xframe) { byte *xframe_end; xpacket_t *pack; byte *p; int len; int ret; if(debug & DBG_COMMANDS) dump_xframe("RX-CMD", xbus, xframe, DBG_ANY); p = xframe->packets; xframe_end = p + XFRAME_LEN(xframe); do { pack = (xpacket_t *)p; len = XPACKET_LEN(pack); /* Sanity checks */ if(unlikely(XPACKET_OP(pack) == XPROTO_NAME(GLOBAL,PCM_READ))) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_DBG(GENERAL, xbus, "A PCM packet within a Non-PCM xframe\n"); dump_xframe("In Non-PCM xframe", xbus, xframe, debug); } ret = -EPROTO; goto out; } p += len; if(p > xframe_end || len < RPACKET_HEADERSIZE) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "Invalid packet length %d\n", len); dump_xframe("BAD LENGTH", xbus, xframe, debug); } ret = -EPROTO; goto out; } ret = packet_process(xbus, pack); if(unlikely(ret < 0)) break; } while(p < xframe_end); out: FREE_RECV_XFRAME(xbus, xframe); return ret; }
static int packet_process(xbus_t *xbus, xpacket_t *pack) { byte op; const xproto_entry_t *xe; xproto_handler_t handler; xproto_table_t *table; xpd_t *xpd; int ret = -EPROTO; BUG_ON(!pack); if(!valid_xpd_addr(&XPACKET_ADDR(pack))) { if(printk_ratelimit()) { XBUS_NOTICE(xbus, "%s: from %d%d: bad address.\n", __FUNCTION__, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); dump_packet("packet_process -- bad address", pack, debug); } goto out; } op = XPACKET_OP(pack); xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); /* XPD may be NULL (e.g: during bus polling */ xe = xproto_global_entry(op); /*-------- Validations -----------*/ if(!xe) { const xproto_table_t *xtable; if(!xpd) { if(printk_ratelimit()) { XBUS_NOTICE(xbus, "%s: from %d%d opcode=0x%02X: no such global command.\n", __FUNCTION__, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack), op); dump_packet("packet_process -- no such global command", pack, 1); } goto out; } xtable = xproto_table(xpd->type); if(!xtable) { if(printk_ratelimit()) XPD_ERR(xpd, "%s: no protocol table (type=%d)\n", __FUNCTION__, xpd->type); goto out; } xe = xproto_card_entry(xtable, op); if(!xe) { if(printk_ratelimit()) { XPD_NOTICE(xpd, "%s: bad command (type=%d,opcode=0x%x)\n", __FUNCTION__, xpd->type, op); dump_packet("packet_process -- bad command", pack, 1); } goto out; } } table = xe->table; BUG_ON(!table); if(!table->packet_is_valid(pack)) { if(printk_ratelimit()) { ERR("xpp: %s: wrong size %d for opcode=0x%02X\n", __FUNCTION__, XPACKET_LEN(pack), op); dump_packet("packet_process -- wrong size", pack, debug); } goto out; } ret = 0; /* All well */ handler = xe->handler; BUG_ON(!handler); XBUS_COUNTER(xbus, RX_BYTES) += XPACKET_LEN(pack); handler(xbus, xpd, xe, pack); out: return ret; }
static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe) { byte *xframe_end; xpacket_t *pack; byte *p; int ret = -EPROTO; /* Assume error */ if(debug & DBG_PCM) dump_xframe("RX_XFRAME_PCM", xbus, xframe, debug); /* handle content */ p = xframe->packets; xframe_end = p + XFRAME_LEN(xframe); do { int len; xpd_t *xpd; pack = (xpacket_t *)p; len = XPACKET_LEN(pack); /* Sanity checks */ if(unlikely(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_READ))) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "%s: Non-PCM packet within a PCM xframe. (%d)\n", __FUNCTION__, rate_limit); dump_xframe("In PCM xframe", xbus, xframe, debug); } goto out; } p += len; if(p > xframe_end || len < RPACKET_HEADERSIZE) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "%s: Invalid packet length %d. (%d)\n", __FUNCTION__, len, rate_limit); dump_xframe("BAD LENGTH", xbus, xframe, debug); } goto out; } xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); if(unlikely(!xpd)) { static int rate_limit; if((rate_limit++ % 1003) == 0) { notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), "RECEIVE PCM"); dump_xframe("Unknown XPD addr", xbus, xframe, debug); } goto out; } if(!pcm_valid(xpd, pack)) goto out; if(SPAN_REGISTERED(xpd)) { XBUS_COUNTER(xbus, RX_PACK_PCM)++; CALL_XMETHOD(card_pcm_tospan, xbus, xpd, pack); } } while(p < xframe_end); ret = 0; /* all good */ XBUS_COUNTER(xbus, RX_XFRAME_PCM)++; out: FREE_RECV_XFRAME(xbus, xframe); return ret; }