/* * channel.cc - Low-level channel functions interacting between the device * and link layers * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: channel.cc,v 1.4 2004/07/30 02:47:51 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include #include "kernel.h" #include "link.h" #include "d_aps_if.h" #include "md5.h" #include "iface.h" #include "bpppoe.h" extern int RegisterChannel(channel_t *); extern void UnregisterChannel(channel_t *); extern void ChannelUp(channel_t *); extern void ChannelOpen(channel_t *); extern void ChannelDown(channel_t *); extern void ChannelConnectComplete(channel_t *, int); extern void DialGotConfig(void *, OptionSet_t *); extern void DialReport(DialResponse_t *); extern policy_t g_policy; /* * Number of registered channels */ static unsigned short nr_channels[2] = {0,250}; #define MAX_KEYS 16 static u8 keys[MAX_KEYS][16]; static int numKeys = 0; u16 next_ldisc = 1; extern "C" { void MD5Init(MD5_CTX *); void MD5Update(MD5_CTX *, unsigned char *, unsigned int); void MD5Final(MD5_CTX *); }; /* * the key is a 32 byte entity, the first 16 bytes of which are 'public' * data, and the last 16 bytes of which are the md5 sum of the public portion * with the secret below. * The first byte of the key is the number of licenses it is valid for. The * rest are completely irrelevant. */ int RegisterMoreChannels(u8 *key) { MD5_CTX md5; MD5Init(&md5); MD5Update(&md5, key, 16); MD5Update(&md5, (unsigned char *) "\x16\xb6\x80\xcb\x1e\xcc\x01\xbe\x32\x1a\x8c\x9d\xaf\x92\x22\x0d" "\x74\xd0\xeb\x60\x29\xbb\x0f\x05\x07\x39\x61\xb1\xd1\x4f\xbe\x79", 32); MD5Final(&md5); if (numKeys < MAX_KEYS && !memcmp(md5.digest, key+16, 16)) { int i; // does this key match any already registered? for (i=0; ilink) { Log(LF_ERROR|LF_IPC, "%s: hannel already registered", ch->device_name); DebugReturn(-EBUSY); } if (ch->dev_class && !strcmp(ch->dev_class, "pppoe")) link = new pppoe_session(ch); else link = new CLink(ch); ch->link = link; if(!link) { Log(LF_ERROR|LF_IPC, "Error allocating memory for link"); DebugReturn(-ENOMEM); } if (ch->link->reopen(1)) { Log(LF_ERROR|LF_IPC, "Error reopening channel: %s", strerror(errno)); delete link; ch->link = NULL; DebugReturn(-EIO); } /* * Set the link options from global defaults */ link->m_ldisc = next_ldisc++; nr_channels[0]++; DebugReturn(0); } void UnregisterChannel(channel_t *ch) { CLink **lh; /* Find the channel on the list */ for(lh = &linkListHead ; *lh != NULL && (*lh)->m_channel != ch ; lh = &(*lh)->m_next ) ; if (!*lh) { Log(LF_ERROR|LF_IPC, "%s: channel not on list!", ch->device_name); return; } /* now that we've found the channel - unregister it */ if(ch->link != NULL) delete (CLink*)ch->link; nr_channels[0]--; } /* * Callback function for GetConfig. Takes the * returned OptionSet_t and matches a link */ void DialGotConfig(void *, OptionSet_t *options) { CLink *tch = linkListHead; DialResponse_t *dr; int i; DebugEnter("DialGotConfig()"); dr = new DialResponse_t; if(dr == NULL) { Log(LF_DEBUG|LF_CALL, "Out of memory"); DebugVoidReturn; } dr->call = options->call; if (!options->is_valid) { strcpy(dr->msg, "No valid config entry"); dr->status = -2; goto out_failed; } Log(LF_DEBUG|LF_IPC, "Got valid configuration (Call_Ident %p)", options->call); // // Do the matching here // if (options->call->ch) { tch = options->call->ch->link; } else if(options->port[0] != '\0') { // // We have a port to match on // Log(LF_DEBUG|LF_IPC, "Attempting to match on port %s", options->port); while((tch != NULL) && (strcmp(options->port, tch->m_channel->device_name) != 0)) tch = tch->m_next; } else if(options->dev_class[0] != '\0') { int retry = 1; // // Attempting a match on device class // Log(LF_DEBUG|LF_IPC, "Attempting to match on port %s", options->dev_class); while((tch != NULL) && ((strcmp(options->dev_class, tch->m_channel->dev_class) != 0) || (tch->m_channel->state != CS_IDLE))) tch = tch->m_next; if (!tch && retry && !strcmp(options->dev_class, "pppoe")) { tch = new pppoe_session(NULL, 0, NULL); if (tch->reopen(0)) { /* failed to open? */ delete tch; tch = NULL; } } } else { // // Just try to find an idle link to dial on // Log(LF_DEBUG|LF_IPC, "Attempting to find idle link"); while((tch != NULL) && (tch->m_channel->state != CS_IDLE)) tch = tch->m_next; } if ((tch == NULL) || (tch->m_channel->state != CS_IDLE)) { // // No link // Log(LF_NOTICE|LF_IPC, "%s: Link in use or no link available, cancelled", options->site); strcpy(dr->msg, "No matching channel available"); dr->status = -2; goto out_failed; } // // We found a link to dial on // // // First set the policy for the session if // necessary // if (options->pol) { SetPolicy(PSCOPE_SESSION, tch->m_channel->device_name, options->pol); delete options->pol; options->pol = NULL; } tch->m_interface = FindIfaceDialing(options->call); /* static interface a link *should* be added to */ tch->Open(); tch->ifOptions.Set(*options); Log(LF_DEBUG|LF_IPC, "Netmask = %x", tch->ifOptions.netmask); // Copy in the real port and class name strcpy(tch->ifOptions.dev_class, tch->m_channel->dev_class); strcpy(tch->ifOptions.port, tch->m_channel->device_name); // Dial the link for (i=0; tch->ifOptions.phone[i] || (-1 != (i = -1)); i++) if (('/' == tch->ifOptions.phone[i] || ';' == tch->ifOptions.phone[i]) && !(tch->ifOptions.phone[i] = 0)) break; Log(LF_INFO|LF_IPC, "%s: Dialing %s... (%s)", tch->m_channel->device_name, tch->ifOptions.phone, tch->ifOptions.site); Log(LF_DEBUG|LF_IPC, "Config is %s %s", tch->ifOptions.is_valid ? "Valid" : "Invalid", options->is_valid ? "Valid" : "Invalid"); dr->status = 0; strcpy(dr->msg, "Dialing..."); DialReport(dr); if (tch->ifOptions.phone[0]) { dr->status = tch->Connect(tch->ifOptions.phone, tch->ifOptions.call_info); if (dr->status) { sprintf(dr->msg, "Connect: %d", dr->status); dr->status = -2; DialReport(dr); RemoveLinkDialing(options->call); tch->m_interface = NULL; } } else { strcpy(dr->msg, "Invalid phone number"); dr->status = -2; DialReport(dr); RemoveLinkDialing(options->call); tch->m_interface = NULL; } if (i != -1) tch->ifOptions.phone[i] = '/'; delete dr; DebugVoidReturn; out_failed: DialReport(dr); RemoveLinkDialing(options->call); delete dr; DebugVoidReturn; }