OpenSS7 SS7 for the Common Man |
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
||||||||||||||||||||||||||
Home | Overview | Status | News | Documentation | Resources | About | |||||||||||||||||||||
File /code/strss7/drivers/slm/slm.c#ident "@(#) $RCSfile: slm.c,v $ $Name: $($Revision: 0.8.2.3 $) $Date: 2003/04/03 19:51:16 $" static char const ident[] = "$RCSfile: slm.c,v $ $Name: $($Revision: 0.8.2.3 $) $Date: 2003/04/03 19:51:16 $"; /* * This is an SLM (Signalling Link Management) multiplexing driver which also * supports M2UA. It has two purposes: 1) to act as an MTP Level 2 * signalling link management layer for OpenSS7 MTP2 drivers; and, 2) to * implement the M2UA protocol for the OpenSS7 stack. * * The SLM multiplexing driver is opened by the SS7 Configuration Daemon and * OpenSS7 Signalling Link (SL) drivers are opened and I_PLINKed under the * multiplexor. In addition, the ss7d opens transport streams and forms the * necessary associations and I_PLINKs them under the multiplexor. Transport * streams can either be client streams (going to an M2UA ASP), server * streams (going to an M2UA SG), or peer streams (going to a peer AS or SG). * Transport streams are normally SCTP streams but can also be TCP, SSCOP-MCE * streams, or any stream recognizing TPI connection oriented data primtives * (e.g, a pipe with a suitable module). Users of the M2UA multiplexing * driver may open user streams on the driver and use them in an identical * fashion to an OpenSS7 MTP2 Signalling Link. * * All SL (Signalling Link) user streams opened on the multiplexing driver * are Style 2 drivers. That is, they must be attached to a specific * SDTI/SDLI (Signalling Data Terminal Identifier/Signalling Data Link * Identifier) before being enabled. */ #include <linux/config.h> #include <linux/version.h> #ifdef MODVERSIONS #include <linux/modversions.h> #endif #include <linux/module.h> #include <sys/stream.h> #include <sys/stropts.h> #include <sys/cmn_err.h> #include <sys/dki.h> #include <linux/errno.h> #include <linux/types.h> #include "../debug.h" #include "../bufq.h" #include <ss7/lmi.h> #include <ss7/lmi_ioctl.h> #include <ss7/sdli.h> #include <ss7/sdli_ioctl.h> #include <ss7/sdti.h> #include <ss7/sdti_ioctl.h> #include <ss7/sli.h> #include <ss7/sli_ioctl.h> #include <ss7/ua_lm.h> #include <ss7/ua_lm_ioctl.h> #define SLM_DESCRIP "SLM: SS7/SL (Signalling Link) STREAMS MULTIPLEXING DRIVER." #define SLM_COPYRIGHT "Copyright (c) 1997-2002 OpenSS7 Corporation. All Rights Reserved." #define SLM_DEVICE "Supports the OpenSS7 MTP2 and INET transport drivers." #define SLM_CONTACT "Brian Bidulock <bidulock@openss7.org>" #define SLM_LICENSE "GPL" #define SLM_BANNER SLM_DESCRIP "\n" \ SLM_COPYRIGHT "\n" \ SLM_DEVICE "\n" \ SLM_CONTACT MODULE_AUTHOR(SLM_CONTACT); MODULE_DESCRIPTION(SLM_DESCRIP); MODULE_SUPPORTED_DEVICE(SLM_DEVICE); #ifdef MODULE_LICENSE MODULE_LICENSE(SLM_LICENSE); #endif #ifndef SLM_CMAJOR #error "SLM_CMAJOR must be defined\n" #endif #define SLM_NMAJOR 4 #define SLM_NMINOR 256 #ifndef INT #define INT int #endif typedef void (*bufcall_fnc_t) (long); #define SLM_DRV_ID SLM_CMAJOR #define SLM_DRV_NAME "slm" STATIC struct module_info slm_winfo = { mi_idnum:SLM_DRV_ID, /* Module ID number */ mi_idname:SLM_DRV_NAME "-wr", /* Module name */ mi_minpsz:1, /* Min packet size accepted */ mi_maxpsz:INFPSZ, /* Max packet size accepted */ mi_hiwat:1024, /* Hi water mark */ mi_lowat:0, /* Lo water mark */ }; STATIC struct module_info slm_rinfo = { mi_idnum:SLM_DRV_ID, /* Module ID number */ mi_idname:SLM_DRV_NAME "-rd", /* Module name */ mi_minpsz:1, /* Min packet size accepted */ mi_maxpsz:INFPSZ, /* Max packet size accepted */ mi_hiwat:1024, /* Hi water mark */ mi_lowat:0, /* Lo water mark */ }; STATIC int slm_open(queue_t *, dev_t *, int, int, cred_t *); STATIC int slm_close(queue_t *, mblk_t *); STATIC INT slm_rput(queue_t *, mblk_t *); STATIC INT slm_rsrv(queue_t *, mblk_t *); STATIC struct qinit slm_rinit = { qi_putp:slm_rput, /* Read put (message from below) */ qi_srvp:slm_rsrv, /* Read queue service */ qi_qopen:slm_open, /* Each open */ qi_qclose:slm_close, /* Last close */ qi_minfo:&slm_rinfo, /* Information */ }; STATIC INT slm_wput(queue_t *, mblk_t *); STATIC INT slm_wsrv(queue_t *, mblk_t *); STATIC struct qinit slm_winit = { qi_putp:slm_wput, /* Write put (message from above) */ qi_srvp:slm_wsrv, /* Write queue service */ qi_minfo:&slm_winfo, /* Information */ }; STATIC struct streamtab slm_info = { st_rdinit:&slm_rinit, /* Upper read queue */ st_wrinit:&slm_winit, /* Upper write queue */ st_muxrinit:&slm_rinit, /* Lower read queue */ st_muxwinit:&slm_winit, /* Lower write queue */ }; /* * Queue Return constants */ #define QR_DONE 0 #define QR_ABSORBED 1 #define QR_TRIMMED 2 #define QR_LOOP 3 #define QR_PASSALONG 4 #define QR_PASSFLOW 5 #define QR_DISABLE 6 #define QR_STRIP 7 /* * ========================================================================= * * Private Structure * * ========================================================================= */ typedef struct pp { struct pp *next; /* list linkage */ struct pp **prev; /* list linkage */ struct pp *links; /* structures we have I_LINKed */ size_t refcnt; /* structure reference count */ lis_spin_lock_t lock; /* structure lock */ union { struct { ushort cmajor; /* major device number */ ushort cminor; /* minor device number */ } dev; uint mux; /* multiplexor index for this structure */ } id; queue_t *rq; /* read queue */ queue_t *wq; /* write queue */ queue_t *mq; /* mgmt queue */ lis_spin_lock_t qlock; /* queue lock */ queue_t *userq; /* queue using the queue lock */ queue_t *waitq; /* queue waiting on the queue lock */ uint rbid; /* rd bufcall id */ uint wbid; /* wr bufcall id */ uint state; /* interface state */ uint version; /* interface version */ uint type; /* type of structure */ union { struct sp *sp; /* AS/SG for user/provider */ struct xp *xp; /* default signalling process proxy */ } u; struct { uint t1; /* timer t1 */ uint t2; /* timer t2 */ uint t3; /* timer t3 */ uint t4; /* timer t4 */ uint t5; /* timer t5 */ } timers; /* M2UA timers */ lmi_option_t option; /* LMI protocol variant and options */ struct { bufq_t rb; /* receive buffer */ bufq_t tb; /* transmission buffer */ bufq_t rtb; /* retransmission buffer */ sl_config_t config; /* SL configuration */ sl_notify_t notify; /* SL notification options */ sl_stats_t stats; /* SL statistics */ sl_stats_t stamp; /* SL statistics timestamps */ sl_stats_t statsp; /* SL statistics periods */ } sl; struct { sdt_config_t config; /* SDT configuration */ sdt_notify_t notify; /* SDT notification options */ sdt_stats_t stats; /* SDT statistics */ sdt_stats_t stamp; /* SDT statistics timestamps */ sdt_stats_t statsp; /* SDT statistics periods */ } sdt; struct { sdl_config_t config; /* SDT configuration */ sdl_notify_t notify; /* SDT notification options */ sdl_stats_t stats; /* SDT statistics */ sdl_stats_t stamp; /* SDT statistics timestamps */ sdl_stats_t statsp; /* SDT statistics periods */ } sdl; } pp_t; typedef pp_t dp_t; typedef pp_t lp_t; STATIC dp_t *slmua_open_list = NULL; /* list of all opened streams */ STATIC lp_t *slmua_link_list = NULL; /* list of all linked streams */ #define PRIV(__q) ((pp_t *)(__q)->q_ptr) #define SLM_TYPE_NONE 0 /* no type assigned yet */ #define SLM_TYPE_LM 1 /* Layer Management stream */ #define SLM_TYPE_SS7U 2 /* SS7 User stream */ #define SLM_TYPE_SS7P 3 /* SS7 Provider stream */ #define SLM_TYPE_ASP 4 /* SIGTRAN ASP transport stream */ #define SLM_TYPE_SGP 5 /* SIGTRAN SGP transport stream */ #define SLM_TYPE_XPP 6 /* SIGTRAN peer transport stream */ typedef struct xp { struct xp *next; /* list linkage */ struct xp **prev; /* list linkage */ uint refcnt; /* structure reference count */ lis_spin_lock_t lock; /* structure lock */ struct pp *pp; /* stream structure for this XP */ struct gp *gp; /* graph of SP for this XP */ struct sp *sp; /* SP for this XP */ uint id; /* ASP Id */ uint state; /* state */ uint level; /* protocol level */ uint version; /* protocol version */ bufq_t buf; /* buffer for failovers */ } xp_t; typedef xp_t asp_t; typedef xp_t sgp_t; typedef xp_t spp_t; STATIC asp_t *slm_asp_list = NULL; /* list of ASP proxies */ STATIC sgp_t *slm_sgp_list = NULL; /* list of SGP proxies */ STATIC spp_t *slm_spp_list = NULL; /* list of SPP proxies */ #define ASP_DOWN 0 #define ASP_INACTIVE 1 #define ASP_ACTIVE 2 #define ASP_WACK_BEAT 3 /* T(beat) timer running */ #define ASP_WACK_ASPUP 4 /* T(ack) timer running */ #define ASP_WACK_ASPDN 5 /* T(ack) timer running */ #define ASP_WACK_ASPAC 6 /* T(ack) timer running */ #define ASP_WACK_ASPIA 7 /* T(ack) timer running */ typedef struct gp { struct { struct xp *xp; /* this XP associated with this SP */ struct gp *next; /* next XP associated with this SP */ struct gp **prev; /* prev XP associated with this SP */ } xp; struct { struct sp *sp; /* this SP associated with this SP */ struct gp *next; /* next SP associated with this SP */ struct gp **prev; /* prev SP associated with this SP */ } sp; uint refcnt; /* structure reference count */ lis_spin_lock_t lock; /* structure lock */ uint state; /* state of this XP in this SP */ uint loadshare; /* loadshare selector (stripe) */ uint broadcast; /* broadcast selector (mirror) */ uint priority; /* priority of this XP for this SP */ uint cost; /* cost of using this XP for this SP */ uint t_beat; /* timer for heartbeats */ uint t_ack; /* timer for ack of messages */ } gp_t; typedef struct np { struct { struct sp *as; /* this AS associated with this SG */ struct np *next; /* next AS associated with this SG */ struct np **prev; /* prev AS associated with this SG */ } as; struct { struct sp *sg; /* this SG associated with this AS */ struct np *next; /* next SG associated with this AS */ struct np **prev; /* prev SG associated with this AS */ } sg; uint refcnt; /* structure reference count */ lis_spin_lock_t lock; /* structure lock */ uint id; /* id for this AS in this SG (RC/IID) */ uint state; /* state of this SG serving this AS */ uint loadshare; /* loadshare selector (stripe) */ uint broadcast; /* broadcast selector (mirror) */ uint priority; /* priority of this SG for this AS */ uint cost; /* cost of this SG for this AS */ } np_t; typedef struct sp { struct sp *next; /* list linkage */ struct sp **prev; /* list linkage */ uint refcnt; /* structure reference count */ lis_spin_lock_t lock; /* structure lock */ struct np *np; /* graph of peer nodes for this node */ struct gp *gp; /* graph of AS/SG for this node */ struct pp *pp; /* list of SS7U/SS7P for this node */ uint id; /* ASP Id used or expected */ uint state; /* state of htis node */ uint tmode; /* traffic mode */ uint min_count; /* minimum number of active stripes */ uint max_count; /* maximum number of active stripes */ uint xpdn_count; /* XPs in down state */ uint xpia_count; /* XPs in inactive state */ uint xpac_count; /* XPs in active state */ } sp_t; typedef sp_t as_t; typedef sp_t sg_t; #define AS_DOWN 0 #define AS_INACTIVE 1 #define AS_ACTIVE 2 #define AS_PENDING 3 #define AS_BLOCKED 4 /* * ------------------------------------------------------------------------- * * Private structure allocation and deallocation * * ------------------------------------------------------------------------- */ STATIC kmem_cache_t *slm_pp_cachep = NULL; STATIC kmem_cache_t *slm_gp_cachep = NULL; STATIC kmem_cache_t *slm_np_cachep = NULL; STATIC kmem_cache_t *slm_sp_cachep = NULL; STATIC kmem_cache_t *slm_xp_cachep = NULL; /* * Cache allocation * ------------------------------------------------------------------------- */ STATIC int slm_term_caches(void) { if (slm_pp_cachep) { if (kmem_cache_destroy(slm_pp_cachep)) cmn_err(CE_WARN, "%s: did not destroy slm_pp_cachep", __FUNCTION__); else printd(("SLM: destroyed slm_pp_cache\n")); } if (slm_gp_cachep) { if (kmem_cache_destroy(slm_gp_cachep)) cmn_err(CE_WARN, "%s: did not destroy slm_gp_cachep", __FUNCTION__); else printd(("SLM: destroyed slm_gp_cache\n")); } if (slm_np_cachep) { if (kmem_cache_destroy(slm_np_cachep)) cmn_err(CE_WARN, "%s: did not destroy slm_np_cachep", __FUNCTION__); else printd(("SLM: destroyed slm_np_cache\n")); } if (slm_sp_cachep) { if (kmem_cache_destroy(slm_sp_cachep)) cmn_err(CE_WARN, "%s: did not destroy slm_sp_cachep", __FUNCTION__); else printd(("SLM: destroyed slm_sp_cache\n")); } if (slm_xp_cachep) { if (kmem_cache_destroy(slm_xp_cachep)) cmn_err(CE_WARN, "%s: did not destroy slm_xp_cachep", __FUNCTION__); else printd(("SLM: destroyed slm_xp_cache\n")); } return; } STATIC int slm_init_caches(void) { if (!slm_pp_cachep && !(slm_pp_cachep = kmem_cache_create ("slm_pp_cachep", sizeof(pp_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) { cmn_err(CE_PANIC, "%s: Cannot allocate slm_pp_cachep", __FUNCTION__); slm_term_caches(); return (-ENOMEM); } else printd(("SLM: initialized pp structure cache\n")); if (!slm_gp_cachep && !(slm_gp_cachep = kmem_cache_create ("slm_gp_cachep", sizeof(pp_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) { cmn_err(CE_PANIC, "%s: Cannot allocate slm_gp_cachep", __FUNCTION__); slm_term_caches(); return (-ENOMEM); } else printd(("SLM: initialized gp structure cache\n")); if (!slm_np_cachep && !(slm_np_cachep = kmem_cache_create ("slm_np_cachep", sizeof(pp_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) { cmn_err(CE_PANIC, "%s: Cannot allocate slm_np_cachep", __FUNCTION__); slm_term_caches(); return (-ENOMEM); } else printd(("SLM: initialized np structure cache\n")); if (!slm_sp_cachep && !(slm_sp_cachep = kmem_cache_create ("slm_sp_cachep", sizeof(pp_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) { cmn_err(CE_PANIC, "%s: Cannot allocate slm_sp_cachep", __FUNCTION__); slm_term_caches(); return (-ENOMEM); } else printd(("SLM: initialized sp structure cache\n")); if (!slm_xp_cachep && !(slm_xp_cachep = kmem_cache_create ("slm_xp_cachep", sizeof(pp_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) { cmn_err(CE_PANIC, "%s: Cannot allocate slm_xp_cachep", __FUNCTION__); slm_term_caches(); return (-ENOMEM); } else printd(("SLM: initialized xp structure cache\n")); return (0); } /* * Private structure allocation * ------------------------------------------------------------------------- */ STATIC pp_t *slm_alloc_priv(queue_t * q, queue_t * mq, pp_t ** ppp, uint index, cred_t * crp, uint type) { pp_t *pp; if ((pp = kmem_cache_alloc(slm_pp_cachep, SLAB_ATOMIC))) { printd(("SLM: allocated device private structure\n")); bzero(pp, sizeof(*pp)); pp->id.mux = index; RD(q)->q_ptr = pp; pp->refcnt++; WR(q)->q_ptr = pp; pp->refcnt++; pp->rq = RD(q); pp->wq = WR(q); pp->mq = mq; lis_spin_lock_init(&pp->qlock, "pp-queue-lock"); pp->userq = NULL; pp->waitq = NULL; pp->rbid = 0; pp->wbid = 0; pp->state = LMI_UNATTACHED; pp->version = 1; pp->type = type; lis_spin_lock_init(&pp->lock, "pp-priv-lock"); if ((pp->next = *ppp)) { pp->next->prev = &pp->next; pp->refcnt++; } *ppp = pp; pp->refcnt++; printd(("SLM: setting private structure defaults\n")); } else ptrace(("SLM: ERROR: Could not allocate device private structure\n")); return (pp); } STATIC void slm_free_priv(queue_t * q) { pp_t *pp = PRIV(q); int flags = 0; ensure(pp, return); lis_spin_lock_irqsave(&pp->lock, &flags); { if (pp->rbid) { unbufcall(xchg(&pp->rbid, 0)); pp->refcnt--; } if (pp->wbid) { unbufcall(xchg(&pp->wbid, 0)); pp->refcnt--; } if ((*pp->prev = pp->next)) { pp->next->prev = pp->prev; pp->refcnt--; } pp->refcnt--; pp->next = NULL; pp->prev = NULL; RD(q)->q_ptr = NULL; pp->refcnt--; WR(q)->q_ptr = NULL; pp->refcnt--; } lis_spin_unlock_irqrestore(&pp->lock, &flags); printd(("SLM: unlinked device private structure\n")); if (pp->refcnt) { assure(pp->refcnt == 0); printd(("SLM: WARNING: pp->refcnt = %d\n", pp->refcnt)); } kmem_cache_free(slm_pp_cachep, pp); printd(("SLM: freed device private structure\n")); return; } /* * AS/SG Node map structure allocation * ------------------------------------------------------------------------- */ STATIC np_t *slm_alloc_np(sp_t * as, sp_t * sg) { np_t *mp; if ((np = kmem_cache_alloc(slm_np_cachep, SLAB_ATOMIC))) { printd(("M2UA: allocated np structure\n")); bzero(np, sizeof(*np)); if ((np->as.next = as->np)) { np->as.next->as.prev = &np->as.next; np->refcnt++; } as->np = np; np->refcnt++; np->as.as = as; as->refcnt++; np->as.prev = &as->np; if ((np->sg.next = sg->np)) { np->sg.next->sg.prev = &np->sg.next; np->refcnt++; } sg->np = np; np->refcnt++; np->sg.sg = sg; sg->refcnt++; np->sg.prev = &sg->np; lis_spin_lock_init(&np->lock); np->state = AS_DOWN; printd(("SLM: setting np structure defaults\n")); } else ptrace(("SLM: ERROR: Could not allocate np structure\n")); return (np); } STATIC void slm_free_np(np_t * np) { int flags = 0; ensure(np, return); lis_spin_lock_irqsave(&np->lock, &flags); { if ((*np->as.prev = np->as.next)) { np->as.next->as.prev = np->as.prev; np->refcnt--; } np->as.as->refcnt--; np->as.as = NULL; np->as.next = NULL; np->as.prev = NULL; if ((*np->sg.prev = np->sg.next)) { np->sg.next->sg.prev = np->sg.prev; np->refcnt--; } np->sg.sg->refcnt--; np->sg.sg = NULL; np->sg.next = NULL; np->sg.prev = NULL; } lis_spin_unlock_irqrestore(&np->lock, &flags); printd(("SLM unlinked np structure\n")); if (np->refcnt) { assure(np->refcnt == 0); printd(("SLM: WARNING: np->refcnt = %d\n", np->refcnt)); } kmem_cache_free(slm_np_cachep, np); printd(("SLM: freed np struture\n")); return; } /* * XP/SP Graph map structure allocation * ------------------------------------------------------------------------- */ STATIC gp_t *slm_alloc_gp(sp_t * sp, xp_t * xp) { gp_t *mp; if ((gp = kmem_cache_alloc(slm_gp_cachep, SLAB_ATOMIC))) { printd(("SLM: allocated gp structure\n")); bzero(gp, sizeof(*gp)); if ((gp->xp.next = xp->gp)) { gp->xp.next->xp.prev = &gp->xp.next; gp->refcnt++; } xp->gp = gp; gp->refcnt++; gp->xp.xp = xp; xp->refcnt++; gp->xp.prev = &xp->gp; if ((gp->sp.next = sp->gp)) { gp->sp.next->sp.prev = &gp->sp.next; gp->refcnt++; } sp->gp = gp; gp->refcnt++; gp->sp.sp = sp; sp->refcnt++; gp->sp.prev = &sp->gp; lis_spin_lock_init(&gp->lock); printd(("SLM: setting gp structure defaults\n")); gp->state = AS_DOWN; } else ptrace(("SLM: ERROR: Could not allocate gp structure\n")); return (gp); } STATIC void slm_free_gp(gp_t * gp) { int flags = 0; ensure(gp, return); lis_spin_lock_irqsave(&gp->lock, &flags); { if ((*gp->xp.prev = gp->xp.next)) { gp->xp.next->xp.prev = gp->xp.prev; gp->refcnt--; } gp->xp.xp->refcnt--; gp->xp.xp = NULL; gp->xp.next = NULL; gp->xp.prev = NULL; if ((*gp->sp.prev = gp->sp.next)) { gp->sp.next->sp.prev = gp->sp.prev; gp->refcnt--; } gp->sp.sp->refcnt--; gp->sp.sp = NULL; gp->sp.next = NULL; gp->sp.prev = NULL; } lis_spin_unlock_irqrestore(&gp->lock, &flags); printd(("SLM unlinked gp structure\n")); if (gp->refcnt) { assure(gp->refcnt == 0); printd(("SLM: WARNING: gp->refcnt = %d\n", gp->refcnt)); } kmem_cache_free(slm_gp_cachep, gp); printd(("SLM: freed gp struture\n")); return; } /* * AS/SG structure allocation * ------------------------------------------------------------------------- */ STATIC sp_t *slm_alloc_sp(sp_t ** spp) { sp_t *sp; if ((sp = kmem_cache_alloc(slm_sp_cachep, SLAB_ATOMIC))) { printd(("SLM: allocated sp structure\n")); bzero(sp, sizeof(*sp)); if ((sp->next = *spp)) { sp->next->prev = &sp->next; sp->refcnt++; } *spp = sp; sp->refcnt++; sp->prev = spp; lis_spin_lock_init(&sp->lock); printd(("SLM: setting sp structure defaults\n")); sp->state = AS_DOWN; // sp->tmode = UA_TMODE_OVERRIDE; sp->min_count = 1; sp->max_count = -1UL; } else ptrace(("SLM: ERROR: Could not allocate sp structure\n")); return (sp); } STATIC void slm_free_sp(sp_t * sp) { int flags = 0; ensure(sp, return); lis_spin_lock_irqsave(&sp->lock, &flags); { if ((*sp->prev = sp->next)) { sp->next->prev = sp->prev; sp->refcnt--; } sp->next = NULL; sp->prev = NULL; while (sp->np) slm_free_np(sp->np); while (sp->gp) slm_free_gp(sp->gp); while (sp->pp) slm_free_pp(sp->pp); } lis_spin_unlock_irqrestore(&sp->lock, &flags); printd(("SLM: unlinked sp structure\n")); if (sp->refcnt) { assure(sp->refcnt == 0); printd(("SLM: WARNING: sp->refcnt = %d\n", sp->refcnt)); } kmem_cache_free(slm_sp_cachep, sp); printd(("SLM: freed sp structure\n")); return; } /* * ASP/SGP/SPP structure allocation * ------------------------------------------------------------------------- */ STATIC xp_t *slm_alloc_xp(sp_t * sp) { xp_t *xp; if ((xp = kmem_cache_alloc(slm_xp_cachep, SLAB_ATOMIC))) { printd(("SLM: allocated xp structure\n")); bzero(xp, sizeof(*xp)); if ((xp->next = *xpp)) { xp->next->prev = &xp->next; xp->refcnt++; } *xpp = xp; xp->refcnt++; xp->prev = xpp; xp->sp = sp; sp->refcnt++; lis_spin_lock_init(&xp->lock); bufq_init(&xp->buf); printd(("SLM: setting xp structure defaults\n")); xp->state = ASP_DOWN; } else ptrace(("SLM: ERROR: Could not allocate xp structure\n")); return (xp); } STATIC void slm_free_xp(xp_t * xp) { int flags = 0; ensure(xp, return); lis_spin_lock_irqsave(&xp->lock, &flags); { if ((*xp->prev = xp->next)) { xp->next->prev = xp->prev; xp->refcnt--; } xp->next = NULL; xp->prev = NULL; while (xp->gp) slm_free_gp(xp->gp); if (xp->pp) { pp_t *pp = xp->pp; pp->u.xp = NULL; xp->refcnt--; xp->pp = NULL; pp->refcnt--; } if (xp->sp) { sp_t *sp = xp->sp; xp->sp = NULL; sp->refcnt--; } } lis_spin_unlock_irqrestore(&xp->lock, &flags); printd(("SLM: unlinked xp structure\n")); if (xp->refcnt) { assure(xp->refcnt == 0); printd(("SLM: WARNING: xp->refcnt = %d\n", xp->refcnt)); } kmem_cache_free(slm_xp_cachep, xp); printd(("SLM: freed xp structure\n")); return; } /* * ======================================================================== * * Locking * * ======================================================================== */ STATIC INLINE int slm_trylockq(queue_t * q) { int res; pp_t *pp = PRIV(q); if (!(res = lis_spin_trylock(&pp->qlock))) { if (q == pp->rq) pp->rwait = q; if (q == pp->wq) pp->wwait = q; } return (res); } STATIC INLINE void slm_unlockq(queue_t * q) { pp_t *pp = PRIV(q); lis_spin_unlock(&pp->qlock); if (pp->rwait) qenable(xchg(&pp->rwait, NULL)); if (pp->wwait) qenable(xchg(&pp->wwait, NULL)); } /* * ========================================================================= * * BUFFER Allocation * * ========================================================================= */ /* * BUFSRV * ----------------------------------- */ STATIC void slm_bufsrv(long data) { queue_t *q = (queue_t *) data; if (q) { pp_t *pp = PRIV(q); if (q == pp->rq) if (pp->rbid) { pp->rbid = 0; pp->refcnt--; } if (q == pp->wq) if (pp->wbid) { pp->wbid = 0; pp->refcnt--; } qenable(q); } } /* * ALLOCB * ----------------------------------- */ STATIC mblk_t *slm_allocb(queue_t * q, size_t size, int prior) { mblk_t *mp; if ((mp = allocb(size, prior))) return (mp); else { pp_t *pp = PRIV(q); if (q == pp->rq) { if (!pp->rbid) { pp->rbid = bufcall(size, prior, &slm_bufsrv, (long) q); pp->refcnt++; } return (NULL); } if (q == pp->wq) { if (!pp->wbid) { pp->wbid = bufcall(size, prior, &slm_bufsrv, (long) q); pp->refcnt++; } return (NULL); } swerr(); return (NULL); } } /* * ESBALLOC * ----------------------------------- */ STATIC mblk_t *slm_esballoc(queue_t * q, unsigned char *base, size_t size, int prior, frtn_t * frtn) { mblk_t *mp; if ((mp = esballoc(base, size, prior, frtn))) return (mp); else { pp_t *pp = PRIV(q); if (q == pp->rq) { if (!pp->rbid) { pp->rbid = esbbcall(prior, &slm_bufsrv, (long) q); pp->refcnt++; } return (NULL); } if (q == pp->wq) { if (!pp->wbid) { pp->wbid = esbbcall(prior, &slm_bufsrv, (long) q); pp->refcnt++; } return (NULL); } swerr(); return (NULL); } } /* * ========================================================================= * * PRIMITIVES Sent Upstream (Upper) or Downstream (Lower) * * ========================================================================= * * PRIMITIVES Sent Upstream (Upper) to SS7 User * ------------------------------------------------------------------------- */ /* * M_ERROR * ----------------------------------- */ STATIC int m_error(queue_t * q, int err) { mblk_t *mp; if ((mp = slm_allocb(q, 2, BPRI_MED))) { mp->b_datap->db_type = M_ERROR; *(mp->b_wptr)++ = err < 0 ? -err : err; *(mp->b_wptr)++ = err < 0 ? -err : err; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * M_HANGUP * ----------------------------------- */ STATIC int m_error(queue_t * q, int err) { mblk_t *mp; if ((mp = slm_allocb(q, 2, BPRI_MED))) { mp->b_datap->db_type = M_HANGUP; *(mp->b_wptr)++ = err < 0 ? -err : err; *(mp->b_wptr)++ = err < 0 ? -err : err; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_PDU_IND * ----------------------------------- */ STATIC INLINE int sl_pdu_ind(queue_t * q, mblk_t * dp, uint prior) { if (canputnext(q)) { mblk_t *mp; sl_pdu_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_PDU_IND; p->sl_mp = prior; mp->b_cont = dp; putnext(q, mp); return (QR_ABSORBED); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * SL_LINK_CONGESTED_IND * ----------------------------------- */ STATIC INLINE int sl_link_congested_ind(queue_t * q, ulong cong, ulong disc) { mblk_t *mp; sl_link_cong_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_LINK_CONGESTED_IND; p->sl_cong_status = cong; p->sl_disc_status = disc; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_LINK_CONGESTION_CEASED_IND * ----------------------------------- */ STATIC INLINE int sl_link_congestion_ceased_ind(queue_t * q, ulong cong, ulong disc) { mblk_t *mp; sl_link_cong_ceased_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_LINK_CONGESTION_CEASED_IND; p->sl_timestamp = jiffies; p->sl_cong_status = cong; p->sl_disc_status = disc; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_RETRIEVED_MESSAGE_IND * ----------------------------------- */ STATIC INLINE int sl_retrieved_message_ind(queue_t * q, mblk_t * dp) { mblk_t *mp; sl_retrieved_msg_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_RETRIEVED_MESSAGE_IND; mp->b_cont = dp; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_RETRIEVAL_COMPLETE_IND * ----------------------------------- */ STATIC INLINE int sl_retrieval_complete_ind(queue_t * q) { mblk_t *mp; sl_retrieval_comp_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_RETRIEVAL_COMPLETE_IND; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_RB_CLEARED_IND * ----------------------------------- */ STATIC INLINE int sl_rb_cleared_ind(queue_t * q) { mblk_t *mp; sl_rb_cleared_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_RB_CLEARED_IND; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_BSNT_IND * ----------------------------------- */ STATIC INLINE int sl_bsnt_ind(queue_t * q, ulong bsnt) { mblk_t *mp; sl_bsnt_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_BSNT_IND; p->sl_bsnt = bsnt; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_IN_SERVICE_IND * ----------------------------------- */ STATIC INLINE int sl_in_service_ind(queue_t * q) { mblk_t *mp; sl_in_service_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_IN_SERVICE_IND; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_OUT_OF_SERVICE_IND * ----------------------------------- */ STATIC INLINE int sl_out_of_service_ind(queue_t * q, ulong reason) { mblk_t *mp; sl_out_of_service_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_OUT_OF_SERVICE_IND; p->sl_timestamp = jiffies; p->sl_reason = reason; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_REMOTE_PROCESSOR_OUTAGE_IND * ----------------------------------- */ STATIC INLINE int sl_remote_processor_outage_ind(queue_t * q) { mblk_t *mp; sl_rem_proc_out_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_REMOTE_PROCESSOR_OUTAGE_IND; p->sl_timestamp = jiffies; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_REMOTE_PROCESSOR_RECOVERED_IND * ----------------------------------- */ STATIC INLINE int sl_remote_processor_recovered_ind(queue_t * q) { mblk_t *mp; sl_rem_proc_recovered_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_REMOTE_PROCESSOR_RECOVERED_IND; p->sl_timestamp = jiffies; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_RTB_CLEARED_IND * ----------------------------------- */ STATIC INLINE int sl_rtb_cleared_ind(queue_t * q) { mblk_t *mp; sl_rtb_cleared_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_RTB_CLEARED_IND; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_RETRIEVAL_NOT_POSSIBLE_IND * ----------------------------------- */ STATIC INLINE int sl_retrieval_not_possible_ind(queue_t * q) { mblk_t *mp; sl_retrieval_not_poss_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_RETRIEVAL_NOT_POSSIBLE_IND; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_BSNT_NOT_RETRIEVABLE_IND * ----------------------------------- */ STATIC INLINE int sl_bsnt_not_retrievable_ind(queue_t * q, ulong bsnt) { mblk_t *mp; sl_bsnt_not_retr_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_BSNT_NOT_RETRIEVABLE_IND; p->sl_bsnt = bsnt; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #if 0 /* * SL_OPTMGMT_ACK * ----------------------------------- */ STATIC INLINE int sl_optmgmt_ack(queue_t * q, caddr_t opt_ptr, size_t opt_len, ulong flags) { mblk_t *mp; sl_optmgmt_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p) + opt_len, BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_OPTMGMT_ACK; p->opt_length = opt_len; p->opt_offset = opt_len ? sizeof(*p) : 0; p->mgmt_flags = flags; bcopy(opt_ptr, mp->b_wptr, opt_len); mp->b_wptr += opt_len; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SL_NOTIFY_IND * ----------------------------------- */ STATIC INLINE int sl_notify_ind(queue_t * q) { mblk_t *mp; sl_notify_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sl_primitive = SL_NOTIFY_IND; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #endif /* * LMI_INFO_ACK * ----------------------------------- */ STATIC INLINE int lmi_info_ack(queue_t * q, caddr_t ppa_ptr, size_t ppa_len) { pp_t *pp = PRIV(q); mblk_t *mp; lmi_info_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p) + ppa_len, BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_INFO_ACK; p->lmi_version = 1; p->lmi_state = pp->state; p->lmi_max_sdu = INFPSZ; p->lmi_min_sdu = 3; p->lmi_header_len = 0; p->lmi_ppa_style = LMI_STYLE2; bcopy(ppa_ptr, mp->b_wptr, ppa_len); mp->b_wptr += ppa_len; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_OK_ACK * ----------------------------------- */ STATIC INLINE int lmi_ok_ack(queue_t * q, ulong state, long prim) { pp_t *pp = PRIV(q); mblk_t *mp; lmi_ok_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_OK_ACK; p->lmi_correct_primitive = prim; p->lmi_state = pp->state = state; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_ERROR_ACK * ----------------------------------- */ STATIC INLINE int lmi_error_ack(queue_t * q, ulong state, long prim, ulong errno, ulong reason) { pp_t *pp = PRIV(q); mblk_t *mp; lmi_error_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_ERROR_ACK; p->lmi_errno = errno; p->lmi_reason = reason; p->lmi_error_primitive = prim; p->lmi_state = pp->state = state; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_ENABLE_CON * ----------------------------------- */ STATIC INLINE int lmi_enable_con(queue_t * q) { mblk_t *mp; lmi_enable_con_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { pp_t *pp = PRIV(q); mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_ENABLE_CON; p->lmi_state = pp->state = LMI_ENABLED; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_DISABLE_CON * ----------------------------------- */ STATIC INLINE int lmi_disable_con(queue_t * q) { mblk_t *mp; lmi_disable_con_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { pp_t *pp = PRIV(q); mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_DISABLE_CON; p->lmi_state = pp->state = LMI_DISABLED; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_OPTMGMT_ACK * ----------------------------------- */ STATIC INLINE int lmi_optmgmt_ack(queue_t * q, ulong flags, caddr_t opt_ptr, size_t opt_len) { mblk_t *mp; lmi_optmgmt_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p) + opt_len, BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_OPTMGMT_ACK; p->lmi_opt_length = opt_len; p->lmi_opt_offset = opt_len ? sizeof(*p) : 0; p->lmi_mgmt_flags = flags; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_ERROR_IND * ----------------------------------- */ STATIC INLINE int lmi_error_ind(queue_t * q, ulong errno, ulong reason) { pp_t *pp = PRIV(q); mblk_t *mp; lmi_error_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_ERROR_IND; p->lmi_errno = errno; p->lmi_reason = reason; p->lmi_state = pp->state; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_STATS_IND * ----------------------------------- */ STATIC INLINE int lmi_stats_ind(queue_t * q, ulong interval) { if (canputnext(q)) { mblk_t *mp; lmi_stats_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_STATS_IND; p->lmi_interval = interval; p->lmi_timestamp = jiffies; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * LMI_EVENT_IND * ----------------------------------- */ STATIC INLINE int lmi_event_ind(queue_t * q, ulong oid, ulong level) { if (canputnext(q)) { mblk_t *mp; lmi_event_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_EVENT_IND; p->lmi_objectid = oid; p->lmi_timestamp = jiffies; p->lmi_severity = level; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * PRIMITIVES Sent Upstream (Upper) to Layer Management * ------------------------------------------------------------------------- */ /* * LM_LINK_IND * ----------------------------------- * Indicates to management that an indication has been received on a linked * stream which it is incapable of handling. We normally do not use this. * It is more typical to place the indication back on the stream and issue an * LM_ERROR_IND to management to let management know that the stream should * be unlinked and dealt with directly. We should consider tunneling IOCTLs * instead of these mechanisms. */ STATIC INLINE int lm_link_ind(queue_t * q, mblk_t * dp) { mblk_t *mp; lm_link_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->prim = LM_LINK_IND; mp->b_cont = dp; putnext(q, mp); return (QR_ABSORBED); } rare(); return (-ENOBUFS); } /* * LM_OK_ACK * ----------------------------------- * Used by the driver to indicate success of a primitive issued by local or * layer management. */ STATIC INLINE int lm_ok_ack(queue_t * q, ulong prim) { mblk_t *mp; lm_ok_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->prim = LM_OK_ACK; p->correct_prim = prim; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LM_ERROR_ACK * ----------------------------------- * Used by the driver to indicate failure of a primitive issues by local or * layer management. */ STATIC INLINE int lm_error_ack(queue_t * q, ulong prim, ulong type, ulong error) { mblk_t *mp; lm_error_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->prim = LM_ERROR_ACK; p->error_prim = prim; p->lm_error = type; p->unix_error = error; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LM_REG_IND * ----------------------------------- * Indicate to management that a registration requires has been received from * an ASP with the specified protocol id and ASP id and the indicated routing * keys. If the registration request is acceptable, management responds with * an LM_REG_RES indicating the configured application server by interface * id. If the registration request fails, management responds with an * LM_REG_REF refusing the request. */ STATIC INLINE int lm_reg_ind(queue_t * q, ulong index, ulong id, ulong load, caddr_t key_ptr, size_t key_len) { if (canputnext(q, mp)) { mblk_t *mp; lm_reg_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p) + key_len, BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->prim = LM_REG_IND; p->muxid = index; p->aspid = id; p->load = load; p->prio = prio; p->KEY_number = keyno; p->KEY_offset = key_len ? sizeof(*p) : 0; p->KEY_length = key_len; bcopy(key_ptr, mp->b_wptr, key_len); mp->b_wptr += key_len; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * LM_DEREG_IND * ----------------------------------- * Indicate to management that a deregistration has been received from an * ASP which was previously registered. */ STATIC INLINE int lm_dereg_ind(queue_t * q, ulong index) { if (canputnext(q, mp)) { mblk_t *mp; lm_dereg_ind_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->prim = LM_DEREG_IND; p->muxid = index; putnext(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * LM_ERROR_IND * ----------------------------------- * Indicate to mangement that an error has occured associated with a link. */ STATIC INLINE int lm_error_ind(queue_t * q, ulong type, ulong error) { mblk_t *mp; lm_error_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->prim = LM_ERROR_IND; p->lm_error = type; p->unix_error = error; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LM_INFO_ACK * ----------------------------------- * Inidcate requested information to management. */ STATIC INLINE int lm_info_ack(queue_t * q, ulong id) { mblk_t *mp; lm_info_ack_t *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->prim = LM_INFO_ACK; p->spid = id; qreply(q, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * PRIMITIVES Sent Downstream (Lower) to Transport * ------------------------------------------------------------------------- */ /* * T_DATA_REQ * ----------------------------------- */ STATIC INLINE int t_data_req(queue_t * q, mblk_t * dp, uint more) { if (canputnext(q)) { mblk_t *mp; struct T_data_req *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = T_DATA_REQ; p->MORE_flag = more; mp->b_cont = dp; putnext(q, mp); return (QR_ABSORBED); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * T_EXDATA_REQ * ----------------------------------- */ STATIC INLINE int t_exdata_req(queue_t * q, mblk_t * dp, uint more) { if (bcanputnext(q, 1)) { mblk_t *mp; struct T_exdata_req *p; if ((mp = slm_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; mp->b_band = 1; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = T_EXDATA_REQ; p->MORE_flag = more; mp->b_cont = dp; putnext(q, mp); return (QR_ABSORBED); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * T_OPTDATA_REQ * ------------------------------------------- */ STATIC INLINE int t_optdata_req(queue_t * q, mblk_t * dp, uint flags, caddr_t opt_ptr, size_t opt_len) { if (((flags & T_ODF_EX) && bcanputnext(q, 1)) || (!(flags & T_ODF_EX) && canputnext(q))) { mblk_t *mp; struct T_optdata_req *p; if ((mp = slm_allocb(q, sizeof(*p) + opt_len, BPRI_MED))) { mp->b_datap->db_type = M_PROTO; mp->b_band = (flags & T_ODF_EX) ? 1 : 0; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = T_OPTDATA_REQ; p->DATA_flag = flags; p->OPT_length = opt_len; p->OPT_offset = opt_len ? sizeof(*p) : 0; bcopy(opt_ptr, mp->b_wptr, opt_len); mp->b_wptr += opt_len; mp->b_cont = dp; putnext(q, mp); return (QR_ABSORBED); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * ------------------------------------------------------------------------- * * M2UA MESSAGE Encoder * * ------------------------------------------------------------------------- */ STATIC int slm_send_data(queue_t * q, mblk_t * mp) { return slm_maup_data(q, -1, mp->b_cont); } /* * SL_PDU_REQ: * ----------------------------------- */ STATIC int slm_pdu_req(queue_t * q, mblk_t * mp) { sl_pdu_req_t *p = (typeof(p)) mp->b_rptr; return slm_maup_data(q, p->sl_message_priority, mp->b_cont); } /* * SL_EMERGENCY_REQ: * ----------------------------------- */ STATIC int slm_emergency_req(queue_t * q, mblk_t * mp) { return slm_maup_state_req(q, M2UA_STATUS_EMER_SET); } /* * SL_EMERGENCY_CEASES_REQ: * ----------------------------------- */ STATIC int slm_emergency_ceases_req(queue_t * q, mblk_t * mp) { return slm_maup_stats_req(q, M2UA_STATUS_EMERG_CLEAR); } /* * SL_START_REQ: * ----------------------------------- */ STATIC int slm_start_req(queue_t * q, mblk_t * mp) { return slm_maup_estab_req(q); } /* * SL_STOP_REQ: * ----------------------------------- */ STATIC int slm_stop_req(queue_t * q, mblk_t * mp) { return slm_maup_rel_req(q); } /* * SL_RETRIEVE_BSNT_REQ: * ----------------------------------- */ STATIC int slm_retrieve_bsnt_req(queue_t * q, mblk_t * mp) { return slm_maup_retr_req(q, M2UA_ACTION_RTRV_BSN, 0); } /* * SL_RETRIEVAL_REQUEST_AND_FSNC_REQ: * ----------------------------------- */ STATIC int slm_retrieval_request_and_fsnc_req(queue_t * q, mblk_t * mp) { sl_retrieval_request_and_fsnc_req_t *p; return slm_maup_retr_req(q, M2UA_ACTION_RTRV_MSGS, p->sl_fsnc); } /* * SL_RESUME_REQ: * ----------------------------------- */ STATIC int slm_resume_req(queue_t * q, mblk_t * mp) { return slm_maup_state_req(q, M2UA_STATUS_LPO_CLEAR); } /* * SL_CLEAR_BUFFERS_REQ: * ----------------------------------- */ STATIC int slm_clear_buffers_req(queue_t * q, mblk_t * mp) { return slm_maup_state_req(q, M2UA_STATUS_FLUSH_BUFFERS); } /* * SL_CLEAR_RTB_REQ: * ----------------------------------- */ STATIC int slm_clear_rtb_req(queue_t * q, mblk_t * mp) { return slm_maup_state_req(q, M2UA_STATUS_CLEAR_RTB); } /* * SL_LOCAL_PROCESSOR_OUTAGE_REQ: * ----------------------------------- */ STATIC int slm_local_processor_outage_req(queue_t * q, mblk_t * mp) { return slm_maup_state_req(q, M2UA_STATUS_LPO_SET); } /* * SL_CONGESTION_DISCARD_REQ: * ----------------------------------- */ STATIC int slm_congestion_discard_req(queue_t * q, mblk_t * mp) { return slm_maup_state_req(q, M2UA_STATUS_CONG_DISCARD); } /* * SL_CONGESTION_ACCEPT_REQ: * ----------------------------------- */ STATIC int slm_congestion_accept_req(queue_t * q, mblk_t * mp) { return slm_maup_state_req(q, M2UA_STATUS_CONG_ACCEPT); } /* * SL_NO_CONGESTION_REQ: * ----------------------------------- */ STATIC int slm_no_congestion_req(queue_t * q, mblk_t * mp) { return slm_maup_state_req(q, M2UA_STATUS_CONG_CLEAR); } /* * SL_POWER_ON_REQ: * ----------------------------------- */ STATIC int slm_power_on_req(queue_t * q, mblk_t * mp) { return (QR_DONE); /* not necessary? */ } /* * SL_OPTMGMT_REQ: * ----------------------------------- */ STATIC int slm_optmgmt_req(queue_t * q, mblk_t * mp) { } /* * SL_NOTIFY_REQ: * ----------------------------------- */ STATIC int slm_notify_req(queue_t * q, mblk_t * mp) { } /* * LMI_INFO_REQ: * ----------------------------------- */ STATIC int slm_info_req(queue_t * q, mblk_t * mp) { } /* * LMI_ATTACH_REQ: * ----------------------------------- */ STATIC int slm_attach_req(queue_t * q, mblk_t * mp) { } /* * LMI_DETACH_REQ: * ----------------------------------- */ STATIC int slm_detach_req(queue_t * q, mblk_t * mp) { } /* * LMI_ENABLE_REQ: * ----------------------------------- */ STATIC int slm_enable_req(queue_t * q, mblk_t * mp) { } /* * LMI_DISABLE_REQ: * ----------------------------------- */ STATIC int slm_disable_req(queue_t * q, mblk_t * mp) { } /* * LMI_OPTMGMT_REQ: * ----------------------------------- */ STATIC int slm_optmgmt_req(queue_t * q, mblk_t * mp) { } /* * SL_PDU_IND: * ----------------------------------- */ STATIC int slm_pdu_ind(queue_t * q, mblk_t * mp) { } /* * SL_LINK_CONGESTED_IND: * ----------------------------------- */ STATIC int slm_link_congested_ind(queue_t * q, mblk_t * mp) { } /* * SL_LINK_CONGESTION_CEASED_IND: * ----------------------------------- */ STATIC int slm_link_congestion_ceased_ind(queue_t * q, mblk_t * mp) { } /* * SL_RETRIEVED_MESSAGE_IND: * ----------------------------------- */ STATIC int slm_retrieved_message_ind(queue_t * q, mblk_t * mp) { } /* * SL_RETRIEVAL_COMPLETE_IND: * ----------------------------------- */ STATIC int slm_retrieval_complete_ind(queue_t * q, mblk_t * mp) { } /* * SL_RB_CLEARED_IND: * ----------------------------------- */ STATIC int slm_rb_cleared_ind(queue_t * q, mblk_t * mp) { } /* * SL_BSNT_IND: * ----------------------------------- */ STATIC int slm_bsnt_ind(queue_t * q, mblk_t * mp) { } /* * SL_IN_SERVICE_IND: * ----------------------------------- */ STATIC int slm_in_service_ind(queue_t * q, mblk_t * mp) { } /* * SL_OUT_OF_SERVICE_IND: * ----------------------------------- */ STATIC int slm_out_of_service_ind(queue_t * q, mblk_t * mp) { } /* * SL_REMOTE_PROCESSOR_OUTAGE_IND: * ----------------------------------- */ STATIC int slm_remote_processor_outage_ind(queue_t * q, mblk_t * mp) { } /* * SL_REMOTE_PROCESSOR_RECOVERED_IND: * ----------------------------------- */ STATIC int slm_remote_processor_recovered_ind(queue_t * q, mblk_t * mp) { } /* * SL_RTB_CLEARED_IND: * ----------------------------------- */ STATIC int slm_rtb_cleared_ind(queue_t * q, mblk_t * mp) { } /* * SL_RETRIEVAL_NOT_POSSIBLE_IND: * ----------------------------------- */ STATIC int slm_retrieval_not_possible_ind(queue_t * q, mblk_t * mp) { } /* * SL_BSNT_NOT_RETRIEVABLE_IND: * ----------------------------------- */ STATIC int slm_bsnt_not_retrievable_ind(queue_t * q, mblk_t * mp) { } /* * SL_OPTMGMT_ACK: * ----------------------------------- */ STATIC int slm_optmgmt_ack(queue_t * q, mblk_t * mp) { } /* * SL_NOTIFY_IND: * ----------------------------------- */ STATIC int slm_notify_ind(queue_t * q, mblk_t * mp) { } /* * LMI_INFO_ACK: * ----------------------------------- */ STATIC int slm_info_ack(queue_t * q, mblk_t * mp) { } /* * LMI_OK_ACK: * ----------------------------------- */ STATIC int slm_ok_ack(queue_t * q, mblk_t * mp) { } /* * LMI_ERROR_ACK: * ----------------------------------- */ STATIC int slm_error_ack(queue_t * q, mblk_t * mp) { } /* * LMI_ENABLE_CON: * ----------------------------------- */ STATIC int slm_enable_con(queue_t * q, mblk_t * mp) { } /* * LMI_DISABLE_CON: * ----------------------------------- */ STATIC int slm_disable_con(queue_t * q, mblk_t * mp) { } /* * LMI_OPTMGMT_ACK: * ----------------------------------- */ STATIC int slm_optmgmt_ack(queue_t * q, mblk_t * mp) { } /* * LMI_ERROR_IND: * ----------------------------------- */ STATIC int slm_error_ind(queue_t * q, mblk_t * mp) { } /* * LMI_STATS_IND: * ----------------------------------- */ STATIC int slm_stats_ind(queue_t * q, mblk_t * mp) { } /* * LMI_EVENT_IND: * ----------------------------------- */ STATIC int slm_event_ind(queue_t * q, mblk_t * mp) { } STATIC int slm_t_w_data(queue_t * q, mblk_t * mp) { return slm_send_data(q, mp); } STATIC int slm_t_w_proto(queue_t * q, mblk_t * mp) { ulong prim = (*(ulong *) mp->b_rptr); if (pp->type == SLM_TYPE_XPP || pp->type = SLM_TYPE_SGP) { switch (prim) { case SL_PDU_REQ: return slm_pdu_req(q, mp); case SL_EMERGENCY_REQ: return slm_emergency_req(q, mp); case SL_EMERGENCY_CEASES_REQ: return slm_emergency_ceases_req(q, mp); case SL_START_REQ: return slm_start_req(q, mp); case SL_STOP_REQ: return slm_stop_req(q, mp); case SL_RETRIEVE_BSNT_REQ: return slm_retrieve_bsnt_req(q, mp); case SL_RETRIEVAL_REQUEST_AND_FSNC_REQ: return slm_retrieval_request_and_fsnc_req(q, mp); case SL_RESUME_REQ: return slm_resume_req(q, mp); case SL_CLEAR_BUFFERS_REQ: return slm_clear_buffers_req(q, mp); case SL_CLEAR_RTB_REQ: return slm_clear_rtb_req(q, mp); case SL_LOCAL_PROCESSOR_OUTAGE_REQ: return slm_local_processor_outage_req(q, mp); case SL_CONGESTION_DISCARD_REQ: return slm_congestion_discard_req(q, mp); case SL_CONGESTION_ACCEPT_REQ: return slm_congestion_accept_req(q, mp); case SL_NO_CONGESTION_REQ: return slm_no_congestion_req(q, mp); case SL_POWER_ON_REQ: return slm_power_on_req(q, mp); case SL_OPTMGMT_REQ: return slm_optmgmt_req(q, mp); case SL_NOTIFY_REQ: return slm_notify_req(q, mp); case LMI_INFO_REQ: return slm_info_req(q, mp); case LMI_ATTACH_REQ: return slm_attach_req(q, mp); case LMI_DETACH_REQ: return slm_detach_req(q, mp); case LMI_ENABLE_REQ: return slm_enable_req(q, mp); case LMI_DISABLE_REQ: return slm_disable_req(q, mp); case LMI_OPTMGMT_REQ: return slm_optmgmt_req(q, mp); } } if (pp->type == SLM_TYPE_XPP || pp->type == SLM_TYPE_ASP) { switch (prim) { case SL_PDU_IND: return slm_pdu_ind(q, mp); case SL_LINK_CONGESTED_IND: return slm_link_congested_ind(q, mp); case SL_LINK_CONGESTION_CEASED_IND: return slm_link_congestion_ceased_ind(q, mp); case SL_RETRIEVED_MESSAGE_IND: return slm_retrieved_message_ind(q, mp); case SL_RETRIEVAL_COMPLETE_IND: return slm_retrieval_complete_ind(q, mp); case SL_RB_CLEARED_IND: return slm_rb_cleared_ind(q, mp); case SL_BSNT_IND: return slm_bsnt_ind(q, mp); case SL_IN_SERVICE_IND: return slm_in_service_ind(q, mp); case SL_OUT_OF_SERVICE_IND: return slm_out_of_service_ind(q, mp); case SL_REMOTE_PROCESSOR_OUTAGE_IND: return slm_remote_processor_outage_ind(q, mp); case SL_REMOTE_PROCESSOR_RECOVERED_IND: return slm_remote_processor_recovered_ind(q, mp); case SL_RTB_CLEARED_IND: return slm_rtb_cleared_ind(q, mp); case SL_RETRIEVAL_NOT_POSSIBLE_IND: return slm_retrieval_not_possible_ind(q, mp); case SL_BSNT_NOT_RETRIEVABLE_IND: return slm_bsnt_not_retrievable_ind(q, mp); case SL_OPTMGMT_ACK: return slm_optmgmt_ack(q, mp); case SL_NOTIFY_IND: return slm_notify_ind(q, mp); case LMI_INFO_ACK: return slm_info_ack(q, mp); case LMI_OK_ACK: return slm_ok_ack(q, mp); case LMI_ERROR_ACK: return slm_error_ack(q, mp); case LMI_ENABLE_CON: return slm_enable_con(q, mp); case LMI_DISABLE_CON: return slm_disable_con(q, mp); case LMI_OPTMGMT_ACK: return slm_optmgmt_ack(q, mp); case LMI_ERROR_IND: return slm_error_ind(q, mp); case LMI_STATS_IND: return slm_stats_ind(q, mp); case LMI_EVENT_IND: return slm_event_ind(q, mp); } } swerr(); return (-EOPNOTSUPP); } /* * LM_SG_ADD_REQ: * ----------------------------------- * Requests that the driver add or augment the signalling gateway for the * protocol on whose user or control queue the request was issued. The SG * identifier is for ruther reference (i.e, for subsequent ADD and DEL * requests). The layer or local management queue normally uses this * primitive to add a signalling gateway which does not yet exist. This is * normally only done on a node acting as an ASP. The traffic mode describes * the traffic mode to be used across the SGP making up the SG. For ASP * operation, the aspid is used to indicate the identifier that the ASP will * use when it goes ASPUP for the given SG. Only one ASP is ever assocated * with an SG instance in this way. */ STATIC int lm_sg_add_req(queue_t * q, mblk_t * mp) { int err; sg_t *sg; as_t *as; np_t *np; pp_t *pp = PRIV(q); lm_sg_add_req_t *p = ((typeof(p)) mp->b_rptr); if (mp->b_wptr - mp->b_rptr < sizeof(*p)) goto emsgsize; if (pp->cred.cr_uid != 0) goto eperm; if (!(as = pp->u.sp)) goto efault; /* see if we already have the sg in question */ for (as = pp->u.sp; as; as = as->next) { for (np = as->np; np; np = np->sg.next) { if (pp->sg.sg->id == p->sgid) { /* we already have one */ if ((err = lmi_ok_ack(q, LM_SG_ADD_REQ))) return (err); sg->id = p->sgid; sg->tmode = p->tmode; sg->min_count = 1; sg->max_count = -1UL; for (np = sg->np; np; np = np->as.next) { np->loadshare = p->load; np->prior = p->prior; np->cost = p->cost; } return (QR_DONE); } } } /* create an np to link new sg */ if (!(sg = slm_alloc_sp(&slm_sg_list))) goto enomem; sg->id = p->sgid; sg->state = AS_DOWN; sg->tmode = p->tmode; sg->min_count = 1; sg->max_count = -1UL; /* automatically link the SG to each AS */ for (as = pp->u.sp; as; as = as->next) { if (!(np = slm_alloc_np(as, sg))) goto free_enomem; np->id = 0; np->state = AS_DOWN; np->loadshare = p->load; np->priority = p->prior; np->cost = p->cost; } if ((err = lm_ok_ack(q, LM_SG_ADD_REQ))) goto free_err; return (QR_DONE); free_err: slm_free_sp(sg); return (err); free_enomem: slm_free_sp(sg); enomem: rare(); return (-ENOMEM); emsgsize: return lm_error_ack(q, LM_SG_ADD_REQ, LMI_SYSERR, EMSGSIZE); eperm: return lm_error_ack(q, LM_SG_ADD_REQ, LMI_SYSERR, EPERM); efault: swerr(); return lm_error_ack(q, LM_SG_ADD_REQ, LMI_SYSERR, EFAULT); } /* * LM_SG_DEL_REQ: * ----------------------------------- * Requests that the driver delete the signalling gateway for the protocol on * whose control queue the request was issued. The SG identifier specifies * the existing SG to be deleted. The layer or local management queue * normally uses this rpimitive to delte a signalling gateway which was * previously added with LM_SG_ADD_REQ. If the specified SG does not exist, * the request is silently ignored. */ STATIC int lm_sg_del_req(queue_t * q, mblk_t * mp) { int err; as_t *as; sg_t *sg; np_t *np; pp_t *pp = PRIV(q); lm_sg_del_req_t *p = ((typeof(p)) mp->b_wptr); if (mp->b_wptr - mp->b_rptr < sizeof(*p)) goto emsgsize; if (pp->cred.cr_uid != 0) goto eperm; for (as = pp->u.sp; as; as = as->next) { for (np = as->np; np; np = np->sg.next) { if ((sg = np->sg.sg) && sg->id == p->sgid) { if ((err = lm_ok_ack(q, LM_SG_DEL_REQ))) return (err); slm_free_sp(sg); return (QR_DONE); } } } return lm_ok_ack(q, LM_SG_DEL_REQ); emsgsize: return lm_error_ack(q, LM_SG_DEL_REQ, LMI_SYSERR, EMSGSIZE); } /* * LM_AS_ADD_REQ: * ----------------------------------- * Requests that the driver add or augment the application server for the * protocol on whose control queue the request was issued. The AS identifier * is for further reference (i.e, a subsequent ADD or DEL request). The RC * or IID identifier will be added to the AS if the AS already exists with * the specified AS Id. * * The layer or local management queue normally uses this primitive to add an * application server which does not yet exist at boot time or in response to * the LM_REG_REQ before issuing an LM_REG_RES. * * The optional routing (link) key is only required for statically allocated * Application Servers. This key is used to bind/connect SS7 provider * streams which support the AS or to generate REG REQ to SGP/SPP * proxies. I don't really intend to use this function, but it is there to * support all SIGTRAN UA allocation modes. * * The ASID is provided to uniquely identify the AS within the ASP. * * The RC/IID is only required for statically allocated AS. That is, if * dynamic registration is desired, the RC/IID value should be zero. * * The SGID is provided to provision an AS on an ASP which is serviced by a * remote SG. If the SGID is zero, all SGs which are available to the ASP * will be used for this AS. * * The MUXID is provided to provision an AS on an SGP which is serviced by a * local SS7 provider. The MUXID is the identifier of the local SS7 provider * stream. If there is no local SS7 provider stream, MUXID should be zero. */ STATIC int lm_as_add_req(queue_t * q, mblk_t * mp) { lm_as_add_req_t *p = ((typeof(p)) mp->b_rptr); if (mp->b_wptr - mp->b_rptr < sizeof(*p)) goto emsgsize; if (mp->b_wptr - mp->b_rptr < sizeof(*p) + p->KEY_length) goto emsgsize; if (pp->cred.cr_uid != 0) goto eperm; { int err; pp_t *pp = PRIV(q); as_t *as; np_t *np; /* look for an AS with the same id */ for (as = pp->u.sp; as; as = as->next) { if (as->id == p->asid) { if ((err = lm_ok_ack(q, LM_AS_ADD_REQ))) return (err); } } } emsgsize: return lm_error_ack(q, LM_AS_ADD_REQ, LMI_SYSERR, EMSGSIZE); eperm: return lm_error_ack(q, LM_AS_ADD_REQ, LMI_SYSERR, EPERM); } /* * LM_AS_DEL_REQ: * ----------------------------------- */ STATIC int lm_as_del_req(queue_t * q, mblk_t * mp) { } /* * LM_PROC_ADD_REQ: * ----------------------------------- */ STATIC int lm_proc_add_req(queue_t * q, mblk_t * mp) { } /* * LM_PROC_DEL_REQ: * ----------------------------------- */ STATIC int lm_proc_del_req(queue_t * q, mblk_t * mp) { } /* * LM_LINK_ADD_REQ: * ----------------------------------- */ STATIC int lm_link_add_req(queue_t * q, mblk_t * mp) { } /* * LM_LINK_DEL_REQ: * ----------------------------------- */ STATIC int lm_link_del_req(queue_t * q, mblk_t * mp) { } /* * LM_ROUTE_ADD_REQ: * ----------------------------------- */ STATIC int lm_route_add_req(queue_t * q, mblk_t * mp) { } /* * LM_ROUTE_DEL_REQ: * ----------------------------------- */ STATIC int lm_route_del_req(queue_t * q, mblk_t * mp) { } /* * LM_REG_RES: * ----------------------------------- */ STATIC int lm_reg_res(queue_t * q, mblk_t * mp) { } /* * LM_REG_REF: * ----------------------------------- */ STATIC int lm_reg_ref(queue_t * q, mblk_t * mp) { } /* * LM_INFO_REQ: * ----------------------------------- */ STATIC int lm_info_req(queue_t * q, mblk_t * mp) { } STATIC int lm_m_w_proto(queue_t * q, mblk_t * mp) { ulong prim = (*(ulong *) mp->b_rptr); switch (prim) { case LM_SG_ADD_REQ: return lm_sg_add_req(q, mp); case LM_SG_DEL_REQ: return lm_sg_del_req(q, mp); case LM_AS_ADD_REQ: return lm_as_add_req(q, mp); case LM_AS_DEL_REQ: return lm_as_del_req(q, mp); case LM_PROC_ADD_REQ: return lm_proc_add_req(q, mp); case LM_PROC_DEL_REQ: return lm_proc_del_req(q, mp); case LM_LINK_ADD_REQ: return lm_link_add_req(q, mp); case LM_LINK_DEL_REQ: return lm_link_del_req(q, mp); case LM_ROUTE_ADD_REQ: return lm_route_add_req(q, mp); case LM_ROUTE_DEL_REQ: return lm_route_del_req(q, mp); case LM_REG_RES: return lm_reg_res(q, mp); case LM_REG_REF: return lm_reg_ref(q, mp); case LM_INFO_REQ: return lm_info_req(q, mp); } } /* * ========================================================================= * * PROTOCOL STATE MACHINE FUNCTIONS * * ========================================================================= */ /* * ------------------------------------------------------------------------- * * Timers * * ------------------------------------------------------------------------- */ enum { t1, t2, t3, t4, t5 }; STATIC INLINE mblk_t *slm_alloc_timeout(ulong timer) { mblk_t *mp; if ((mp = allocb(sizeof(ulong), BPRI_HI))) { mp->b_datap->db_type = M_PCRSE; *((ulong) mp->b_wptr)++ = timer; } return (mp); } STATIC void slm_t1_timeout(caddr_t data) { pp_t *pp = (pp_t *) data; if (xchg(&pp->timers.t1, 0)) { mblk_t *mp; if ((mp = slm_alloc_timeout(t1))) { printd(("SLM: t1 timeout at %lu\n", jiffies)); pp->rput(pp->rq, mp); } else { __printd(("SLM: t1 timeout collision\n")); pp->timers.t1 = timeout(&slm_t1_timeout, (cadd_t) pp, 10); /* back off */ } } return; } STATIC void slm_t2_timeout(caddr_t data) { pp_t *pp = (pp_t *) data; if (xchg(&pp->timers.t2, 0)) { mblk_t *mp; if ((mp = slm_alloc_timeout(t2))) { printd(("SLM: t2 timeout at %lu\n", jiffies)); pp->rput(pp->rq, mp); } else { __printd(("SLM: t2 timeout collision\n")); pp->timers.t2 = timeout(&slm_t2_timeout, (cadd_t) pp, 10); /* back off */ } } return; } STATIC void slm_t4_timeout(caddr_t data) { pp_t *pp = (pp_t *) data; if (xchg(&pp->timers.t4, 0)) { mblk_t *mp; if ((mp = slm_alloc_timeout(t4))) { printd(("SLM: t4 timeout at %lu\n", jiffies)); pp->rput(pp->rq, mp); } else { __printd(("SLM: t4 timeout collision\n")); pp->timers.t4 = timeout(&slm_t4_timeout, (cadd_t) pp, 10); /* back off */ } } return; } STATIC void slm_t4_timeout(caddr_t data) { pp_t *pp = (pp_t *) data; if (xchg(&pp->timers.t4, 0)) { mblk_t *mp; if ((mp = slm_alloc_timeout(t4))) { printd(("SLM: t4 timeout at %lu\n", jiffies)); pp->rput(pp->rq, mp); } else { __printd(("SLM: t4 timeout collision\n")); pp->timers.t4 = timeout(&slm_t4_timeout, (cadd_t) pp, 10); /* back off */ } } return; } STATIC void slm_t5_timeout(caddr_t data) { pp_t *pp = (pp_t *) data; if (xchg(&pp->timers.t5, 0)) { mblk_t *mp; if ((mp = slm_alloc_timeout(t5))) { printd(("SLM: t5 timeout at %lu\n", jiffies)); pp->rput(pp->rq, mp); } else { __printd(("SLM: t5 timeout collision\n")); pp->timers.t5 = timeout(&slm_t5_timeout, (cadd_t) pp, 10); /* back off */ } } return; } STATIC INLINE void slm_timer_stop(queue_t * q, const uint t) { pp_t *pp = PRIV(q); int flags = 0; lis_spin_lock_irqsave(&pp->lock, &flags); { switch (t) { case t1: if (pp->timers.t1) { printd(("SLM: stopping t1 at %lu\n", jiffies)); untimeout(xchg(&pp->timers.t1, 0)); } break; case t2: if (pp->timers.t2) { printd(("SLM: stopping t2 at %lu\n", jiffies)); untimeout(xchg(&pp->timers.t2, 0)); } break; case t3: if (pp->timers.t3) { printd(("SLM: stopping t3 at %lu\n", jiffies)); untimeout(xchg(&pp->timers.t3, 0)); } break; case t4: if (pp->timers.t4) { printd(("SLM: stopping t4 at %lu\n", jiffies)); untimeout(xchg(&pp->timers.t4, 0)); } break; case t5: if (pp->timers.t5) { printd(("SLM: stopping t5 at %lu\n", jiffies)); untimeout(xchg(&pp->timers.t5, 0)); } break; } } lis_spin_unlock_irqrestore(&pp->lock, &flags); } STATIC INLINE void slm_timer_start(queue_t * q, const uint t) { pp_t *pp = PRIV(q); int flags = 0; lis_spin_lock_irqsave(&pp->lock, &flags); { slm_timer_stop(q, t); switch (t) { case t1: printd(("SLM: starting t1 %lu ms at %lu\n", pp->config.t1 * 10, jiffies)); pp->timers.t1 = timeout(&slm_t1_timeout, (caddr_t) pp, pp->config.t1); break; case t2: printd(("SLM: starting t2 %lu ms at %lu\n", pp->config.t2 * 10, jiffies)); pp->timers.t2 = timeout(&slm_t2_timeout, (caddr_t) pp, pp->config.t2); break; case t3: printd(("SLM: starting t3 %lu ms at %lu\n", pp->config.t3 * 10, jiffies)); pp->timers.t3 = timeout(&slm_t3_timeout, (caddr_t) pp, pp->config.t3); break; case t4: printd(("SLM: starting t4 %lu ms at %lu\n", pp->config.t4 * 10, jiffies)); pp->timers.t4 = timeout(&slm_t4_timeout, (caddr_t) pp, pp->config.t4); break; case t5: printd(("SLM: starting t5 %lu ms at %lu\n", pp->config.t5 * 10, jiffies)); pp->timers.t5 = timeout(&slm_t5_timeout, (caddr_t) pp, pp->config.t5); break; } } lis_spin_unlock_irqrestore(&pp->lock, &flags); } /* * ------------------------------------------------------------------------- * * SLM State Machines * * ------------------------------------------------------------------------- */ /* * ========================================================================= * * Events from below * * ========================================================================= */ /* * ------------------------------------------------------------------------- * * SLM events from below (timeouts) * * ------------------------------------------------------------------------- */ /* * T1 EXPIRY * ----------------------------------- */ STATIC int slm_t1_expiry(queue_t * q) { pp_t *pp = PRIV(q); (void) pp; fixme(("SLM: FIXME: Implement this function\n")); return (-EFAULT); } /* * T2 EXPIRY * ----------------------------------- */ STATIC int slm_t2_expiry(queue_t * q) { pp_t *pp = PRIV(q); (void) pp; fixme(("SLM: FIXME: Implement this function\n")); return (-EFAULT); } /* * T3 EXPIRY * ----------------------------------- */ STATIC int slm_t3_expiry(queue_t * q) { pp_t *pp = PRIV(q); (void) pp; fixme(("SLM: FIXME: Implement this function\n")); return (-EFAULT); } /* * T4 EXPIRY * ----------------------------------- */ STATIC int slm_t4_expiry(queue_t * q) { pp_t *pp = PRIV(q); (void) pp; fixme(("SLM: FIXME: Implement this function\n")); return (-EFAULT); } /* * T5 EXPIRY * ----------------------------------- */ STATIC int slm_t5_expiry(queue_t * q) { pp_t *pp = PRIV(q); (void) pp; fixme(("SLM: FIXME: Implement this function\n")); return (-EFAULT); } /* * ------------------------------------------------------------------------- * * M2UA Message Decoder * * ------------------------------------------------------------------------- */ STATIC int slm_t_r_data(q, mp) { } STATIC int slm_t_r_proto(q, mp) { switch (*(ulong *) mp->b_rptr) { case T_DISCON_IND: case T_ORDREL_IND: case T_DATA_IND: case T_EXDATA_IND: case T_OPTDATA_IND: default: } } /* * ------------------------------------------------------------------------- * * Transport Events from Below * * ------------------------------------------------------------------------- */ /* * T_DATA_IND * ----------------------------------- */ STATIC int t_data_ind(queue_t * q, mblk_t * mp) { } /* * T_EXDATA_IND * ----------------------------------- */ STATIC int t_exdata_ind(queue_t * q, mblk_t * mp) { } /* * T_OPTDATA_IND * ----------------------------------- */ STATIC int t_optdata_ind(queue_t * q, mblk_t * mp) { } /* * ========================================================================= * * EVENTS From Above * * ========================================================================= */ /* * ------------------------------------------------------------------------- * * EVENTS From SS7 User * * ------------------------------------------------------------------------- */ /* * M_DATA * ----------------------------------- */ STATIC int slm_send_data(queue_t * q, mblk_t * mp) { } /* * Any SL Primitive * ----------------------------------- */ STATIC int sl_prim(q, mp, int (*prim) (queue_t *, mblk_t *)) { pp_t *pp = PRIV(q); if (pp->state != LMI_ENABLED) { pp->state = LMI_UNUSABLE; return m_error(q, EPROTO); } if (pp->link && pp->link->state == LMI_ENABLED) { queue_t *lq = (q == pp->wq) ? pp->link->wq : pp->link->rq; if (mp->b_datap->db_type == M_PCPROTO || canput(lq)) { slm_wput(lq, mp); return (QR_ABSORBED); } rare(); return (-EBUSY); } return prim(q, mp); } /* * SL SEND DATA * ----------------------------------- */ STATIC int sl_send_data(queue_t * q, mblk_t * mp) { } /* * SL_PDU_REQ * ----------------------------------- */ STATIC int sl_pdu_req(queue_t * q, mblk_t * mp) { } /* * SL_EMERGENCY_REQ * ----------------------------------- */ STATIC int sl_emergency_req(queue_t * q, mblk_t * mp) { } /* * SL_EMERGENCY_CEASES_REQ * ----------------------------------- */ STATIC int sl_emergency_ceases_req(queue_t * q, mblk_t * mp) { } /* * SL_START_REQ * ----------------------------------- */ STATIC int sl_start_req(queue_t * q, mblk_t * mp) { } /* * SL_STOP_REQ * ----------------------------------- */ STATIC int sl_stop_req(queue_t * q, mblk_t * mp) { } /* * SL_RETRIEVE_BSNT_REQ * ----------------------------------- */ STATIC int sl_retrieve_bsnt_req(queue_t * q, mblk_t * mp) { } /* * SL_RETREIVAL_REQUEST_AND_FSNC_REQ * ----------------------------------- */ STATIC int sl_retreival_request_and_fsnc_req(queue_t * q, mblk_t * mp) { } /* * SL_RESUME_REQ * ----------------------------------- */ STATIC int sl_resume_req(queue_t * q, mblk_t * mp) { } /* * SL_CLEAR_BUFFERS_REQ * ----------------------------------- */ STATIC int sl_clear_buffers_req(queue_t * q, mblk_t * mp) { } /* * SL_CLEAR_RTB_REQ * ----------------------------------- */ STATIC int sl_clear_rtb_req(queue_t * q, mblk_t * mp) { } /* * SL_LOCAL_PROCESSOR_OUTAGE_REQ * ----------------------------------- */ STATIC int sl_local_processor_outage_req(queue_t * q, mblk_t * mp) { } /* * SL_CONGESTION_DISCARD_REQ * ----------------------------------- */ STATIC int sl_congestion_discard_req(queue_t * q, mblk_t * mp) { } /* * SL_CONGESTION_ACCEPT_REQ * ----------------------------------- */ STATIC int sl_congestion_accept_req(queue_t * q, mblk_t * mp) { } /* * SL_NO_CONGESTION_REQ * ----------------------------------- */ STATIC int sl_no_congestion_req(queue_t * q, mblk_t * mp) { } /* * SL_POWER_ON_REQ * ----------------------------------- */ STATIC int sl_power_on_req(queue_t * q, mblk_t * mp) { } /* * SL_OPTMGMT_REQ * ----------------------------------- */ STATIC int sl_optmgmt_req(queue_t * q, mblk_t * mp) { } /* * SL_NOTIFY_REQ * ----------------------------------- */ STATIC int sl_notify_req(queue_t * q, mblk_t * mp) { } /* * Any LMI Request * ----------------------------------- */ STATIC int lmi_request(q, mp, int (*request) (queue_t *, mblk_t *)) { pp_t *pp = PRIV(q); if (pp->link && pp->link->state == LMI_ENABLED) { queue_t *wq = pp->link->wq; if (mp->b_datap->db_type == M_PCPROTO || canput(wq)) { slm_wput(wq, mp); return (QR_ABSORBED); } rare(); return (-EBUSY); } return request(q, mp); } /* * LMI_ATTACH_REQ * ----------------------------------- */ STATIC int lmi_attach_req(queue_t * q, mblk_t * mp) { } /* * LMI_DETACH_REQ * ----------------------------------- */ STATIC int lmi_detach_req(queue_t * q, mblk_t * mp) { } /* * LMI_ENABLE_REQ * ----------------------------------- */ STATIC int lmi_enable_req(queue_t * q, mblk_t * mp) { } /* * LMI_DISABLE_REQ * ----------------------------------- */ STATIC int lmi_disable_req(queue_t * q, mblk_t * mp) { } /* * LMI_OPMGMT_REQ * ----------------------------------- */ STATIC int lmi_opmgmt_req(queue_t * q, mblk_t * mp) { } /* * ------------------------------------------------------------------------- * * EVENTS From Layer Management * * ------------------------------------------------------------------------- */ /* * ========================================================================= * * IO Controls * * ========================================================================= */ /* * ========================================================================= * * MUX Linking and Unlinking * * ========================================================================= */ STATIC pp_t *slm_links = NULL; /* * I_LINK * ------------------------------------------------------------------------- */ STATIC int slm_i_link(queue_t * q, mblk_t * mp) { if (mp->b_cont) { pp_t *pp = PRIV(q), *lp; struct iocblk *iocp = (typeof(iocp)) mp->b_rptr; struct linkblk *lb = (typeof(lb)) mp->b_cont->b_rptr; queue_t *lq = lb->l_qbot; if (lq->q_ptr != NULL) return (QR_DONE); /* already linked */ if ((lp = slm_alloc_priv(lq, q, &slmlinks, lb->l_index, iocp->ioc_cr, SLM_TYPE_NONE))) { noenable(RD(lq)); noenable(WR(lq)); return (QR_DONE); } return (-ENOMEM); } swerr(); return (-EFAULT); } /* * I_PLINK * ------------------------------------------------------------------------- */ STATIC int slm_i_plink(queue_t * q, mblk_t * mp) { if (mp->b_cont) { pp_t *pp = PRIV(q); struct iocblk *iocp = (typeof(iocp)) mp->b_rptr; struct linkblk *lb = (typeof(lb)) mp->b_cont->b_rptr; if (iocp->ioc_cr->cr_uid != 0) return (-EPERM); return slm_i_link(q, mp); } swerr(); return (-EFAULT); } /* * I_UNLINK * ------------------------------------------------------------------------- */ STATIC int slm_i_unlink(queue_t * q, mblk_t * mp) { if (mp->b_cont) { pp_t *pp = PRIV(q), *lp; struct iocblk *iocp = (typeof(iocp)) mp->b_rptr; struct linkblk *lb = (typeof(lb)) mp->b_cont->b_rptr; queue_t *lq = lb->l_qbot; if (!(lp = lq->q_ptr)) return (QR_DONE); /* already unlinked */ fixme(("SLM: FIXME: check credentials before unlinking\n")); enableok(RD(lq)); enableok(WR(lq)); slm_free_priv(lq); return (QR_DONE); } swerr(); return (-EFAULT); } /* * I_PUNLINK * ------------------------------------------------------------------------- */ STATIC int slm_i_punlink(queue_t * q, mblk_t * mp) { if (mp->b_cont) { pp_t *pp = PRIV(q); struct iocblk *iocp = (typeof(iocp)) mp->b_rptr; struct linkblk *lb = (typeof(lb)) mp->b_cont->b_rptr; if (iocp->ioc_cr->cr_uid != 0) return (-EPERM); return slm_i_unlink(q, mp); } swerr(); return (-EFAULT); } /* * ========================================================================= * * STREAMS Message Handling * * ========================================================================= */ /* * M_IOCTL Handling * ------------------------------------------------------------------------- */ STATIC int slm_w_ioctl(queue_t * q, mblk_t * mp) { pp_t *pp = PRIV(q); struct iocblk *iocp = (struct iocblk *) mp->b_rptr; void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL; int cmd = iocp->ioc_cmd, count = iocp->ioc_count; struct linkblk *lp = (struct linkblk *) arg; int ret = 0; int type = _IOC_TYPE(cmd), nr = _IOC_NR(cmd), size = _IOC_SIZE(cmd); switch (type) { case __SID: switch (pp->type) { case SLM_TYPE_LM: case SLM_TYPE_SS7U: switch (nr) { case _IOC_NR(I_LINK): ret = slm_i_link(q, mp); break; case _IOC_NR(I_PLINK): ret = slm_i_plink(q, mp); break; case _IOC_NR(I_UNLINK): ret = slm_i_unlink(q, mp); break; case _IOC_NR(I_PUNLINK): ret = slm_i_punlink(q, mp); break; default: ptrace(("SLM: ERROR: Unknwon IOCTL %d\n", nr)); case _IOC_NR(I_STR): rare(); (void) lp; ret = -EINVAL; break; } break; default: swerr(); ret = (-EFAULT); break; } break; default: return (QR_PASSALONG); } if (ret >= 0) { mp->b_datap->db_type = M_IOCACK; ioc->ioc_error = 0; ioc->ioc_rval = 0; } else { mp->b_datap->db_type = M_IOCNAK; ioc->ioc_error = -ret; ioc->ioc_rval = -1; } qreply(q, mp); return (QR_ABSORBED); } /* * M_PROTO, M_PCPROTO Handling * ------------------------------------------------------------------------- */ STATIC int slm_w_proto(queue_t * q, mblk_t * mp) { int rtn; ulong prim; pp_t *pp = PRIV(q); ulong oldstate = pp->state; switch (pp->type) { case SLM_TYPE_SS7U: if ((rtn = slm_u_w_proto(q, mp)) != -EOPNOTSUPP) break; case SLM_TYPE_LM: rtn = slm_m_w_proto(q, mp); break; case SLM_TYPE_SS7P: rtn = slm_p_w_proto(q, mp); break; case SLM_TYPE_ASP: case SLM_TYPE_SGP: case SLM_TYPE_XPP: rtn = slm_t_w_proto(q, mp); break; case SLM_TYPE_NONE: rtn = (QR_DISABLE); break; default: swerr(); rtn = (-EFAULT); break; } if (rtn < 0) pp->state = oldstate; return (rtn); } STATIC int slm_r_proto(queue_t * q, mblk_t * mp) { int rtn; ulong prim; pp_t *pp = PRIV(q); ulong oldstate = pp->state; switch (pp->type) { case SLM_TYPE_LM: rtn = slm_m_r_proto(q, mp); break; case SLM_TYPE_SS7U: rtn = slm_u_r_proto(q, mp); break; case SLM_TYPE_SS7P: rtn = slm_p_r_proto(q, mp); break; case SLM_TYPE_ASP: case SLM_TYPE_SGP: case SLM_TYPE_XPP: rtn = slm_t_r_proto(q, mp); break; case SLM_TYPE_NONE: rtn = (QR_DISABLE); break; default: swerr(); rtn = (-EFAULT); break; } if (rtn < 0) pp->state = oldstate; return (rtn); } /* * M_DATA Handling * ------------------------------------------------------------------------- */ STATIC int slm_w_data(queue_t * q, mblk_t * mp) { pp_t *pp = PRIV(q); switch (pp->type) { case SLM_TYPE_LM: return slm_m_w_data(q, mp); case SLM_TYPE_SS7U: return slm_u_w_data(q, mp); case SLM_TYPE_SS7P: return slm_p_w_data(q, mp); case SLM_TYPE_ASP: case SLM_TYPE_SGP: case SLM_TYPE_XPP: return slm_t_w_data(q, mp); case SLM_TYPE_NONE: return (QR_DISABLE); default: swerr(); return (-EFAULT); } } STATIC int slm_r_data(queue_t * q, mblk_t * mp) { pp_t *pp = PRIV(q); switch (pp->type) { case SLM_TYPE_LM: return slm_m_r_data(q, mp); case SLM_TYPE_SS7U: return slm_u_r_data(q, mp); case SLM_TYPE_SS7P: return slm_p_r_data(q, mp); case SLM_TYPE_ASP: case SLM_TYPE_SGP: case SLM_TYPE_XPP: return slm_t_r_data(q, mp); case SLM_TYPE_NONE: return (QR_DISABLE); default: swerr(); return (-EFAULT); } } /* * M_RSE, M_PCRSE Handling * ------------------------------------------------------------------------- */ STATIC int slm_r_pcrse(queue_t * q, mblk_t * mp) { pp_t *pp = PRIV(q); int rtn; int flags; lis_spin_lock_irqsave(&pp->lock, &flags); switch (*(ulong *) mp->b_rptr) { case t1: printd(("SLM: t1 expiry at %lu\n", jiffies)); rtn = sl_t1_expiry(q); break; case t2: printd(("SLM: t2 expiry at %lu\n", jiffies)); rtn = sl_t2_expiry(q); break; case t3: printd(("SLM: t3 expiry at %lu\n", jiffies)); rtn = sl_t3_expiry(q); break; case t4: printd(("SLM: t4 expiry at %lu\n", jiffies)); rtn = sl_t4_expiry(q); break; case t5: printd(("SLM: t5 expiry at %lu\n", jiffies)); rtn = sl_t5_expiry(q); break; default: rtn = -EFAULT; break; } lis_spin_unlock_irqrestore(&pp->lock, &flags); return (rtn); } /* * M_FLUSH Handling * ------------------------------------------------------------------------- */ STATIC INLINE int slm_w_flush(queue_t * q, mblk_t * mp) { pp_t *pp = PRIV(q); fixme(("SLM: FIXME: Make this work for SLM\n")); if (*mp->b_rptr & FLUSHW) { if (pp) { int flags; lis_spin_lock_irqsave(&pp->lock, &flags); if (pp->tx.cmp) { pp->tx.cmp = NULL; pp->tx.repeat = 0; } lis_spin_unlock_irqrestore(&pp->lock, &flags); } if (*mp->b_rptr & FLUSHBAND) flushband(q, mp->b_rptr[1], FLUSHALL); else flushq(q, FLUSHALL); *mp->b_rptr &= ~FLUSHW; } if (*mp->b_rptr & FLUSHR) { if (pp) { int flags; lis_spin_lock_irqsave(&pp->lock, &flags); if (pp->rx.cmp) { freeb(pp->rx.cmp); pp->rx.cmp = NULL; pp->rx.repeat = 0; } lis_spin_unlock_irqrestore(&pp->lock, &flags); } if (*mp->b_rptr & FLUSHBAND) flushband(OTHER(q), mp->b_rptr[1], FLUSHALL); else flushq(OTHER(q), FLUSHALL); qreply(q, mp); return (QR_ABSORBED); } return (QR_DONE); } /* * ========================================================================= * * PUT and SRV * * ========================================================================= */ STATIC INLINE int slm_r_prim(queue_t * q, mblk_t * mp) { if (mp->b_datap->db_type == M_DATA) return slm_w_data(q, mp); switch (mp->b_datap->db_type) { case M_DATA: return slm_w_data(q, mp); case M_PROTO: case M_PCPROTO: return slm_w_proto(q, mp); case M_FLUSH: return slm_w_flush(q, mp); case M_IOCTL: return slm_w_ioctl(q, mp); } return (QR_PASSFLOW); } STATIC INLINE int slm_w_prim(queue_t * q, mblk_t * mp) { if (mp->b_datap->db_type == M_DATA) return slm_r_data(q, mp); switch (mp->b_datap->db_type) { case M_DATA: return slm_r_data(q, mp); case M_RSE: case M_PCRSE: return slm_r_pcrse(q, mp); case M_PROTO: case M_PCPROTO: return slm_r_proto(q, mp); case M_FLUSH: return slm_r_flush(q, mp); } } /* * PUTQ Put Routine * ------------------------------------------------------------------------- */ STATIC INLINE int slm_putq(queue_t * q, mblk_t * mp, int (*proc) (queue_t *, mblk_t *)) { int rtn = 0; if (mp->b_datap->db_type < QPCTL || q->q_count) { // printd(("%s: putting %s on queue\n", q->q_qinfo->qi_minfo->mi_idname, // mname(mp))); putq(q, mp); return (0); } if (slm_trylockq(q)) { do { // printd(("%s: processing priority %s\n", q->q_qinfo->qi_minfo->mi_idname, // mname(mp))); /* Fast Path */ if ((rtn = proc(q, mp)) == QR_DONE) { freemsg(mp); break; } switch (rtn) { case QR_DONE: freemsg(mp); case QR_ABSORBED: break; case QR_STRIP: if (mp->b_cont) putq(q, mp->b_cont); case QR_TRIMMED: freeb(mp); break; case QR_LOOP: if (!q->q_next) { qreply(q, mp); break; } case QR_PASSALONG: if (q->q_next) { putnext(q, mp); break; } // ptrace(("%s: ERROR: couldn't pass message\n", // q->q_qinfo->qi_minfo->mi_idname)); rtn = -EOPNOTSUPP; default: // ptrace(("%s: ERROR: (q dropping) %d\n", // q->q_qinfo->qi_minfo->mi_idname, // rtn)); freemsg(mp); break; case QR_DISABLE: putq(q, mp); rtn = 0; break; case QR_PASSFLOW: if (mp->b_datap->db_type >= QPCTL || canputnext(q)) { putnext(q, mp); break; } case -ENOBUFS: case -EBUSY: case -ENOMEM: case -EAGAIN: putq(q, mp); break; } } while (0); slm_unlockq(q); } else { rare(); // printd(("%s: putting %s on queue\n", q->q_qinfo->qi_minfo->mi_idname, // mname(mp))); putq(q, mp); } return (rtn); } /* * SRVQ Service Routine * ------------------------------------------------------------------------- */ STATIC INLINE int slm_srvq(queue_t * q, int (*proc) (queue_t *, mblk_t *)) { int rtn = 0; ensure(q, return (-EFAULT)); if (slm_trylockq(q)) { mblk_t *mp; while ((mp = getq(q))) { // printd(("%s: processing queued %s\n", q->q_qinfo->qi_minfo->mi_idname, // mname(mp))); /* Fast Path */ if ((rtn = proc(q, mp)) == QR_DONE) { freemsg(mp); continue; } switch (rtn) { case QR_DONE: freemsg(mp); case QR_ABSORBED: continue; case QR_STRIP: if (mp->b_cont) putbq(q, mp->b_cont); case QR_TRIMMED: freeb(mp); continue; case QR_LOOP: if (!q->q_next) { qreply(q, mp); continue; } case QR_PASSALONG: if (q->q_next) { putnext(q, mp); continue; } // ptrace(("%s: ERROR: couldn't pass message\n", // q->q_qinfo->qi_minfo->mi_idname)); rtn = -EOPNOTSUPP; default: // ptrace(("%s: ERROR: (q dropping) %d\n", // q->q_qinfo->qi_minfo->mi_idname, // rtn)); freemsg(mp); continue; case QR_DISABLE: // ptrace(("%s: ERROR: (q disabling) %d\n", // q->q_qinfo->qi_minfo->mi_idname, // rtn)); noenable(q); putbq(q, mp); rtn = 0; break; case QR_PASSFLOW: if (mp->b_datap->db_type >= QPCTL || canputnext(q)) { putnext(q, mp); continue; } case -ENOBUFS: /* proc must have scheduled bufcall */ case -EBUSY: /* proc must have failed canput */ case -ENOMEM: /* proc must have scheduled bufcall */ case -EAGAIN: /* proc must re-enable on some event */ if (mp->b_datap->db_type < QPCTL) { // ptrace(("%s: ERROR: (q stalled) %d\n", // q->q_qinfo->qi_minfo->mi_idname, rtn)); putbq(q, mp); break; } /* * Be careful not to put a priority * message back on the queue. */ if (mp->b_datap->db_type == M_PCPROTO) { mp->b_datap->db_type = M_PROTO; mp->b_band = 255; putq(q, mp); break; } // ptrace(("%s: ERROR: (q dropping) %d\n", // q->q_qinfo->qi_minfo->mi_idname, // rtn)); freemsg(mp); continue; } break; } slm_unlockq(q); } else { rare(); qenable(q); } return (rtn); } STATIC INT slm_rput(queue_t * q, mblk_t * mp) { return (INT) slm_putq(q, mp, &slm_r_prim); } STATIC INT slm_rsrv(queue_t * q) { return (INT) slm_srvq(q, &slm_r_prim); } STATIC INT slm_wput(queue_t * q, mblk_t * mp) { return (INT) slm_putq(q, mp, &slm_w_prim); } STATIC INT slm_wsrv(queue_t * q) { return (INT) slm_srvq(q, &slm_w_prim); } /* * ========================================================================= * * OPEN and CLOSE * * ========================================================================= * Open is called on the first open of a character special device stream * head; close is called on the last close of the same device. */ pp_t *x400p_list = NULL; STATIC int slm_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * crp) { int cmajor = getmajor(*devp); int cminor = getminor(*devp); pp_t *pp, **ppp = &x400p_list; (void) crp; MOD_INC_USE_COUNT; /* keep module from unloading in our face */ if (q->q_ptr != NULL) { MOD_DEC_USE_COUNT; return (0); /* already open */ } if (sflag == MODOPEN || WR(q)->q_next) { ptrace(("SLM: ERROR: Can't open as module\n")); MOD_DEC_USE_COUNT; return (EIO); } if (!cminor) sflag = CLONEOPEN; if (sflag == CLONEOPEN) { printd(("SLM: Clone open in effect on major %d\n", cmajor)); cminor = 1; } for (; *ppp && (*ppp)->id.dev.cmajor < cmajor; ppp = &(*ppp)->next); for (; *ppp && cminor < SLM_NMINOR; ppp = &(*ppp)->next) { ushort dminor = (*ppp)->id.dev.cminor; if (cminor < dminor) break; if (cminor == dminor) { if (sflag != CLONEOPEN) { ptrace(("SLM: ERROR: Requested device in use\n")); MOD_DEC_USE_COUNT; return (ENXIO); } cminor++; } } if (cminor >= SLM_NMINOR) { ptrace(("SLM: ERROR: No device minors left\n")); MOD_DEC_USE_COUNT; return (ENXIO); } printd(("SLM: Opened character device %d:%d\n", cmajor, cminor)); *devp = makedevice(cmajor, cminor); if (!(pp = slm_alloc_priv(q, q, ppp, (uint) (*devp), crp, SLM_TYPE_NONE))) { ptrace(("SLM: ERROR: No memory\n")); MOD_DEC_USE_COUNT; return (ENOMEM); } return (0); } STATIC int slm_close(queue_t * q, int flag, cred_t * crp) { pp_t *pp = PRIV(q); (void) flag; (void) crp; (void) pp; printd(("SLM: Closed character device %d:%d\n", pp->id.dev.cmajor, pp->id.dev.cminor)); slm_free_priv(q); MOD_DEC_USE_COUNT; return (0); } /* * ========================================================================= * * LiS Module Initialization (For unregistered driver.) * * ========================================================================= */ STATIC int slm_initialized = 0; STATIC int slm_majors[SLM_NMAJOR] = { 0, }; STATIC void slm_init(void) { int err, major; unless(slm_initialized, return); cmn_err(CE_NOTE, SLM_BANNER); /* console splash */ if ((err = slm_init_caches())) { cmn_err(CE_PANIC, "SLM: ERROR: Could not allocate caches"); slm_initialized = err; return; } for (major = 0; major < SLM_NMAJOR; major++) { if ((err = lis_register_strdev(SLM_CMAJOR + major, &slm_info, SLM_NMINOR, SLM_DRV_NAME)) <= 0) { cmn_err(CE_WARN, "SLM: ERROR: couldn't register driver for major %d", major + SLM_CMAJOR); slm_initialized = err; for (major -= 1; major >= 0; major--) lis_unregister_strdev(slm_majors[major]); slm_term_caches(); return; } else slm_majors[major] = err; } slm_initialized = SLM_CMAJOR; return; } STATIC void slm_terminate(void) { int err, major; ensure(slm_initialized, return); for (major = 0; major < SLM_NMAJOR; major++) { if (slm_majors[major]) { if ((err = lis_unregister_strdev(slm_majors[major]))) cmn_err(CE_PANIC, "SLM: couldn't unregister driver for major %d\n", slm_majors[major]); else slm_majors[major] = err; } } slm_initialized = 0; slm_term_caches(); return; } /* * ========================================================================= * * Kernel Module Initialization * * ========================================================================= */ int init_module(void) { slm_init(); if (slm_initialized < 0) return slm_initialized; return (0); } void cleanup_module(void) { slm_terminate(); }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |