l2tp_wan.c   [plain text]


/*
 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/* -----------------------------------------------------------------------------
*
*  History :
*
*  Sep 2002 - created from pptp_wan.c.
*
*  Theory of operation :
*
*  this file implements the l2tp driver for the ppp family
*
*  it's the responsability of the driver to update the statistics
*  whenever that makes sense
*     ifnet.if_lastchange = a packet is present, a packet starts to be sent
*     ifnet.if_ibytes = nb of correct PPP bytes received
*     ifnet.if_obytes = nb of correct PPP bytes sent 
*     ifnet.if_ipackets = nb of PPP packet received
*     ifnet.if_opackets = nb of PPP packet sent
*     ifnet.if_ierrors = nb on input packets in error
*     ifnet.if_oerrors = nb on ouptut packets in error
*
----------------------------------------------------------------------------- */


/* -----------------------------------------------------------------------------
Includes
----------------------------------------------------------------------------- */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/sockio.h>
#include <sys/kernel.h>
#include <net/if_types.h>
#include <kern/clock.h>
#include <kern/locks.h>



#include "../../../Family/ppp_domain.h"
#include "../../../Family/if_ppplink.h"
#include "../../../Family/ppp_defs.h"
#include "../../../Family/if_ppp.h"
#include "l2tpk.h"
#include "l2tp_rfc.h"
#include "l2tp_wan.h"


/* -----------------------------------------------------------------------------
Definitions
----------------------------------------------------------------------------- */

struct l2tp_wan {
    /* first, the ifnet structure... */
    struct ppp_link 	link;			/* ppp link structure */

    /* administrative info */
    TAILQ_ENTRY(l2tp_wan) next;
    void 		*rfc;			/* L2TP protocol structure */

    /* settings */
    
    /* output data */

    /* input data */

    /* log purpose */
};

/* -----------------------------------------------------------------------------
Forward declarations
----------------------------------------------------------------------------- */

static int	l2tp_wan_output(struct ppp_link *link, mbuf_t m);
static int 	l2tp_wan_ioctl(struct ppp_link *link, u_long cmd, void *data);

/* -----------------------------------------------------------------------------
Globals
----------------------------------------------------------------------------- */

static TAILQ_HEAD(, l2tp_wan) 	l2tp_wan_head;

extern lck_mtx_t   *ppp_domain_mutex;

/* -----------------------------------------------------------------------------
----------------------------------------------------------------------------- */
int l2tp_wan_init()
{

    TAILQ_INIT(&l2tp_wan_head);
    return 0;
}

/* -----------------------------------------------------------------------------
----------------------------------------------------------------------------- */
int l2tp_wan_dispose()
{

    // don't detach if links are in use
    if (TAILQ_FIRST(&l2tp_wan_head))
        return EBUSY;
        
    return 0;
}

/* -----------------------------------------------------------------------------
attach L2TP interface dlil layer
----------------------------------------------------------------------------- */
int l2tp_wan_attach(void *rfc, struct ppp_link **link)
{
    int 		ret;	
    struct l2tp_wan  	*wan, *wan1;
    struct ppp_link  	*lk;
    u_short 		unit;
	
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);

    // Note : we allocate/find number/insert in queue in that specific order
    // because of funnels and race condition issues

    MALLOC(wan, struct l2tp_wan *, sizeof(struct l2tp_wan), M_TEMP, M_WAITOK);
    if (!wan)
        return ENOMEM;

    bzero(wan, sizeof(struct l2tp_wan));

	// find a unit and where to insert it, keep the list ordered
	unit = 0;
    wan1 = TAILQ_FIRST(&l2tp_wan_head);
    while (wan1) {
    	if (wan1->link.lk_unit > unit)
            break;

		unit = wan1->link.lk_unit + 1;
        wan1 = TAILQ_NEXT(wan1, next);
    }

	if (wan1)
		TAILQ_INSERT_BEFORE(wan1, wan, next);
	else
		TAILQ_INSERT_TAIL(&l2tp_wan_head, wan, next);
		
    lk = (struct ppp_link *) wan;
    
    // it's time now to register our brand new link
    lk->lk_name 	= (u_char*)L2TP_NAME;
    lk->lk_mtu 		= L2TP_MTU;
    lk->lk_mru 		= L2TP_MTU;;
    lk->lk_type 	= PPP_TYPE_L2TP;
    lk->lk_hdrlen 	= 80;	// ??? 
	l2tp_rfc_command(rfc, L2TP_CMD_GETBAUDRATE, &lk->lk_baudrate);
    lk->lk_ioctl 	= l2tp_wan_ioctl;
    lk->lk_output 	= l2tp_wan_output;
    lk->lk_unit 	= unit;
    lk->lk_support 	= 0;
    wan->rfc = rfc;

    ret = ppp_link_attach((struct ppp_link *)wan);
    if (ret) {
        IOLog("L2TP_wan_attach, error = %d, (ld = %p)\n", ret, wan);
        TAILQ_REMOVE(&l2tp_wan_head, wan, next);
        FREE(wan, M_TEMP);
        return ret;
    }
    
    //IOLog("L2TP_wan_attach, link index = %d, (ld = %p)\n", lk->lk_index, lk);

    *link = lk;
    
    return 0;
}

/* -----------------------------------------------------------------------------
detach L2TP interface dlil layer
----------------------------------------------------------------------------- */
void l2tp_wan_detach(struct ppp_link *link)
{
    struct l2tp_wan  	*wan = (struct l2tp_wan *)link;
	
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);

    ppp_link_detach(link);
    TAILQ_REMOVE(&l2tp_wan_head, wan, next);
    FREE(wan, M_TEMP);
}

/* -----------------------------------------------------------------------------
called from l2tp_rfc when data are present
----------------------------------------------------------------------------- */
int l2tp_wan_input(struct ppp_link *link, mbuf_t m)
{
	struct timespec tv;	
    
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
	
    link->lk_ipackets++;
    link->lk_ibytes += mbuf_pkthdr_len(m);
	nanouptime(&tv);
	link->lk_last_recv = tv.tv_sec;
    ppp_link_input(link, m);	
    return 0;
}

/* -----------------------------------------------------------------------------
called from l2tp_rfc when xmit is full
----------------------------------------------------------------------------- */
void l2tp_wan_xmit_full(struct ppp_link *link)
{
	
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);

    link->lk_flags |= SC_XMIT_FULL;
}

/* -----------------------------------------------------------------------------
called from l2tp_rfc when there is an input error
----------------------------------------------------------------------------- */
void l2tp_wan_input_error(struct ppp_link *link)
{
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);

    ppp_link_event(link, PPP_LINK_EVT_INPUTERROR, 0);
}

/* -----------------------------------------------------------------------------
called from l2tp_rfc when xmit is ok again
----------------------------------------------------------------------------- */
void l2tp_wan_xmit_ok(struct ppp_link *link)
{
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
    link->lk_flags &= ~SC_XMIT_FULL;
    ppp_link_event(link, PPP_LINK_EVT_XMIT_OK, 0);
}

/* -----------------------------------------------------------------------------
Process an ioctl request to the ppp interface
----------------------------------------------------------------------------- */
int l2tp_wan_ioctl(struct ppp_link *link, u_long cmd, void *data)
{
    //struct l2tp_wan 	*wan = (struct l2tp_wan *)link;;
    int error = 0;
	
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
    
    //LOGDBG(ifp, ("l2tp_wan_ioctl, cmd = 0x%x\n", cmd));

    switch (cmd) {
        default:
            error = ENOTSUP;
    }
    return error;
}

/* -----------------------------------------------------------------------------
This gets called at splnet from if_ppp.c at various times
when there is data ready to be sent
----------------------------------------------------------------------------- */
int l2tp_wan_output(struct ppp_link *link, mbuf_t m)
{
    struct l2tp_wan 	*wan = (struct l2tp_wan *)link;
    u_int32_t		len = mbuf_pkthdr_len(m);	// take it now, as output will change the mbuf
    int 		err;
	struct timespec tv;	
	
	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
    
    if ((err = l2tp_rfc_output(wan->rfc, m, 0))) {
        link->lk_oerrors++;
        return err;
    }

    link->lk_opackets++;
    link->lk_obytes += len;
	nanouptime(&tv);
	link->lk_last_xmit = tv.tv_sec;
    return 0;
}