/* $Id$ * * Author Karsten Keil (keil@isdn4linux.de) * * This file is (c) under GNU PUBLIC LICENSE * */ #include #include #include #include #include "hisax_core.h" #ifdef CONFIG_KMOD #include #endif hisaxobject_t *hisax_objects = NULL; int core_debug; static int debug; static int obj_id; #ifdef MODULE MODULE_AUTHOR("Karsten Keil"); MODULE_PARM(debug, "1i"); EXPORT_SYMBOL(HiSax_register); EXPORT_SYMBOL(HiSax_unregister); #define HiSaxInit init_module #endif static moditem_t modlist[] = { {"hisaxl1", ISDN_PID_L1_TE_S0}, {"hisaxl2", ISDN_PID_L2_LAPD}, {"hisaxl2", ISDN_PID_L2_B_X75SLP}, {NULL, ISDN_PID_NONE} }; hisaxobject_t * get_object(int id) { hisaxobject_t *obj = hisax_objects; while(obj) { if (obj->id == id) return(obj); obj = obj->next; } return(NULL); } static hisaxobject_t * find_object(int protocol) { hisaxobject_t *obj = hisax_objects; int err; while (obj) { err = obj->own_ctrl(NULL, MGR_HASPROTOCOL | REQUEST, &protocol); if (!err) return(obj); if (err != -ENOPROTOOPT) { if (HasProtocol(obj, protocol)) return(obj); } obj = obj->next; } return(NULL); } static hisaxobject_t * find_object_module(int protocol) { moditem_t *m = modlist; hisaxobject_t *obj; while (m->name != NULL) { if (m->protocol == protocol) { #ifdef CONFIG_KMOD if (debug) printk(KERN_DEBUG "find_object_module %s - trying to load\n", m->name); request_module(m->name); #else printk(KERN_WARNING "not possible to autoload %s please try to load manually\n", m->name); #endif if ((obj = find_object(protocol))) return(obj); } m++; } if (debug) printk(KERN_DEBUG __FUNCTION__": no module for protocol %x found\n", protocol); return(NULL); } static void remove_object(hisaxobject_t *obj) { hisaxstack_t *st = hisax_stacklist; hisaxlayer_t *layer; hisaxinstance_t *inst, *tmp; while (st) { layer = st->lstack; while(layer) { inst = layer->inst; while (inst) { if (inst->obj == obj) { tmp = inst->next; inst->obj->own_ctrl(st, MGR_RELEASE | INDICATION, inst); inst = tmp; } else inst = inst->next; } layer = layer->next; } st = st->next; } } static int dummy_if(hisaxif_t *hif, struct sk_buff *skb) { if (!skb) { printk(KERN_WARNING __FUNCTION__": hif(%p) without skb\n", hif); return(-EINVAL); } if (debug & DEBUG_DUMMY_FUNC) printk(KERN_DEBUG __FUNCTION__": hif(%p) skb(%p) len(%d) prim(%x)\n", hif, skb, skb->len, *((u_int *)skb->data)); dev_kfree_skb_any(skb); return(0); } hisaxinstance_t * get_next_instance(hisaxstack_t *st, hisax_pid_t *pid) { int err; hisaxinstance_t *next; int layer, proto; hisaxobject_t *obj; layer = get_lowlayer(pid->layermask); proto = pid->protocol[layer]; next = get_instance(st, layer, proto); if (!next) { obj = find_object(proto); if (!obj) obj = find_object_module(proto); if (!obj) { printk(KERN_WARNING __FUNCTION__": no object found\n"); return(NULL); } err = obj->own_ctrl(st, MGR_NEWLAYER | REQUEST, pid); if (err) { printk(KERN_WARNING __FUNCTION__": newlayer err(%d)\n", err); return(NULL); } next = get_instance(st, layer, proto); } return(next); } static int sel_channel(hisaxstack_t *st, channel_info_t *ci) { int err = -EINVAL; if (!ci) return(err); printk(KERN_DEBUG __FUNCTION__": st(%p) st->mgr(%p)\n", st, st->mgr); if (st->mgr) { if (st->mgr->obj && st->mgr->obj->own_ctrl) { err = st->mgr->obj->own_ctrl(st->mgr, MGR_SELCHANNEL | REQUEST, ci); printk(KERN_DEBUG __FUNCTION__": MGR_SELCHANNEL(%d)\n", err); } else int_error(); } else { printk(KERN_WARNING __FUNCTION__": no mgr st(%p)\n", st); } if (err) { hisaxstack_t *cst = st->child; int nr = 0; ci->st.p = NULL; if (!(ci->channel & (~CHANNEL_NUMBER))) { /* only number is set */ while(cst) { nr++; if (nr == (ci->channel & 3)) { ci->st.p = cst; err = 0; break; } cst = cst->next; } } } return(err); } static int disconnect_if(hisaxinstance_t *inst, u_int prim, hisaxif_t *hif) { int err = 0; if (hif) { hif->stat = IF_NOACTIV; hif->func = dummy_if; hif->peer = NULL; hif->fdata = NULL; } if (inst) err = inst->obj->own_ctrl(inst, prim, hif); return(err); } static int add_if(hisaxinstance_t *inst, u_int prim, hisaxif_t *hif) { hisaxif_t *myif; if (!inst) return(-EINVAL); if (!hif) return(-EINVAL); if (hif->stat & IF_UP) { myif = &inst->down; } else if (hif->stat & IF_DOWN) { myif = &inst->up; } else return(-EINVAL); APPEND_TO_LIST(hif, myif); inst->obj->own_ctrl(inst, prim, hif); return(0); } static char tmpbuf[4096]; static int debugout(hisaxinstance_t *inst, logdata_t *log) { char *p = tmpbuf; if (log->head && *log->head) p += sprintf(p,"%s ", log->head); else p += sprintf(p,"%s ", inst->obj->name); p += vsprintf(p, log->fmt, log->args); printk(KERN_DEBUG "%s\n", tmpbuf); return(0); } static int get_hdevice(hisaxdevice_t **dev, int *typ) { if (!dev) return(-EINVAL); if (!typ) return(-EINVAL); if (*typ == HISAX_RAW_DEVICE) { *dev = get_free_rawdevice(); if (!(*dev)) return(-ENODEV); return(0); } return(-EINVAL); } static int central_manager(void *data, u_int prim, void *arg) { hisaxstack_t *st = data; switch(prim) { case MGR_NEWSTACK | REQUEST: if (!(st = new_stack(data, arg))) return(-EINVAL); return(0); case MGR_REGLAYER | INDICATION: return(register_layer(st, arg)); case MGR_REGLAYER | REQUEST: if (!register_layer(st, arg)) { hisaxinstance_t *inst = arg; return(inst->obj->own_ctrl(arg, MGR_REGLAYER | CONFIRM, NULL)); } return(-EINVAL); case MGR_UNREGLAYER | REQUEST: return(unregister_instance(data)); case MGR_DISCONNECT | REQUEST: case MGR_DISCONNECT | INDICATION: return(disconnect_if(data, prim, arg)); case MGR_GETDEVICE | REQUEST: return(get_hdevice(data, arg)); case MGR_DELDEVICE | REQUEST: return(free_device(data)); } if (!data) return(-EINVAL); switch(prim) { case MGR_SETSTACK | REQUEST: return(set_stack(st, arg)); case MGR_CLEARSTACK | REQUEST: return(clear_stack(st)); case MGR_DELSTACK | REQUEST: return(release_stack(st)); case MGR_SELCHANNEL | REQUEST: return(sel_channel(st, arg)); case MGR_ADDIF | REQUEST: return(add_if(data, prim, arg)); case MGR_CONNECT | REQUEST: return(ConnectIF(data, arg)); case MGR_LOADFIRM | REQUEST: if (st->mgr && st->mgr->obj && st->mgr->obj->own_ctrl) return(st->mgr->obj->own_ctrl(st->mgr, prim, arg)); break; case MGR_DEBUGDATA | REQUEST: return(debugout(data, arg)); default: printk(KERN_WARNING "manager prim %x not handled\n", prim); break; } return(-EINVAL); } void hisaxlock_core(void) { #ifdef MODULE MOD_INC_USE_COUNT; #endif } void hisaxunlock_core(void) { #ifdef MODULE MOD_DEC_USE_COUNT; #endif } int HiSax_register(hisaxobject_t *obj) { if (!obj) return(-EINVAL); obj->id = obj_id++; APPEND_TO_LIST(obj, hisax_objects); obj->ctrl = central_manager; // register_prop if (debug) printk(KERN_DEBUG "HiSax_register %s id %x\n", obj->name, obj->id); return(0); } int HiSax_unregister(hisaxobject_t *obj) { if (!obj) return(-EINVAL); if (debug) printk(KERN_DEBUG "HiSax_unregister %s %d refs\n", obj->name, obj->refcnt); if (obj->DPROTO.protocol[0]) release_stacks(obj); else remove_object(obj); REMOVE_FROM_LISTBASE(obj, hisax_objects); return(0); } int HiSaxInit(void) { int err; core_debug = debug; err = init_hisaxdev(debug); return(err); } #ifdef MODULE void cleanup_module(void) { hisaxstack_t *st; free_hisaxdev(); if (hisax_objects) { printk(KERN_WARNING "hisaxcore hisax_objects not empty\n"); } if (hisax_stacklist) { printk(KERN_WARNING "hisaxcore hisax_stacklist not empty\n"); st = hisax_stacklist; while (st) { printk(KERN_WARNING "hisaxcore st %x in list\n", st->id); if (st == st->next) { printk(KERN_WARNING "hisaxcore st == next\n"); break; } st = st->next; } } printk(KERN_DEBUG "hisaxcore unloaded\n"); } #endif