lkml.org 
[lkml]   [2020]   [Nov]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH net-next v2 2/6] net/x25: make neighbour params configurable
    Date
    Extended struct x25_neigh and x25_subscrip_struct to configure following
    params through SIOCX25SSUBSCRIP:
    o mode (DTE/DCE)
    o number of channels
    o facilities (packet size, window size)
    o timer T20

    Based on this configuration options the following changes/extensions
    where made:
    o DTE/DCE handling to select the next lc (DCE=from bottom / DTE=from
    top)
    o DTE/DCE handling to set correct clear/reset/restart cause
    o take default facilities from neighbour settings

    Signed-off-by: Martin Schiller <ms@dev.tdt.de>
    ---

    Change from v1:
    o fix 'subject_prefix' and 'checkpatch' warnings
    o fix incompatible assignment of 'struct compat_x25_facilities'

    ---
    include/net/x25.h | 8 ++-
    include/uapi/linux/x25.h | 56 ++++++++-------
    net/x25/af_x25.c | 145 ++++++++++++++++++++++++++++++++-------
    net/x25/x25_facilities.c | 6 +-
    net/x25/x25_link.c | 97 ++++++++++++++++++++++----
    net/x25/x25_subr.c | 22 +++++-
    6 files changed, 268 insertions(+), 66 deletions(-)

    diff --git a/include/net/x25.h b/include/net/x25.h
    index 4c1502e8b2b2..ec00f595fcc6 100644
    --- a/include/net/x25.h
    +++ b/include/net/x25.h
    @@ -140,6 +140,9 @@ struct x25_neigh {
    struct net_device *dev;
    unsigned int state;
    unsigned int extended;
    + unsigned int dce;
    + unsigned int lc;
    + struct x25_facilities facilities;
    struct sk_buff_head queue;
    unsigned long t20;
    struct timer_list t20timer;
    @@ -164,6 +167,8 @@ struct x25_sock {
    struct timer_list timer;
    struct x25_causediag causediag;
    struct x25_facilities facilities;
    + /* set, if facilities changed by SIOCX25SFACILITIES */
    + unsigned int socket_defined_facilities;
    struct x25_dte_facilities dte_facilities;
    struct x25_calluserdata calluserdata;
    unsigned long vc_facil_mask; /* inc_call facilities mask */
    @@ -215,7 +220,8 @@ int x25_create_facilities(unsigned char *, struct x25_facilities *,
    struct x25_dte_facilities *, unsigned long);
    int x25_negotiate_facilities(struct sk_buff *, struct sock *,
    struct x25_facilities *,
    - struct x25_dte_facilities *);
    + struct x25_dte_facilities *,
    + struct x25_neigh *);
    void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);

    /* x25_forward.c */
    diff --git a/include/uapi/linux/x25.h b/include/uapi/linux/x25.h
    index 034b7dc5593a..094dc2cff37b 100644
    --- a/include/uapi/linux/x25.h
    +++ b/include/uapi/linux/x25.h
    @@ -63,31 +63,6 @@ struct sockaddr_x25 {
    struct x25_address sx25_addr; /* X.121 Address */
    };

    -/*
    - * DTE/DCE subscription options.
    - *
    - * As this is missing lots of options, user should expect major
    - * changes of this structure in 2.5.x which might break compatibilty.
    - * The somewhat ugly dimension 200-sizeof() is needed to maintain
    - * backward compatibility.
    - */
    -struct x25_subscrip_struct {
    - char device[200-sizeof(unsigned long)];
    - unsigned long global_facil_mask; /* 0 to disable negotiation */
    - unsigned int extended;
    -};
    -
    -/* values for above global_facil_mask */
    -
    -#define X25_MASK_REVERSE 0x01
    -#define X25_MASK_THROUGHPUT 0x02
    -#define X25_MASK_PACKET_SIZE 0x04
    -#define X25_MASK_WINDOW_SIZE 0x08
    -
    -#define X25_MASK_CALLING_AE 0x10
    -#define X25_MASK_CALLED_AE 0x20
    -
    -
    /*
    * Routing table control structure.
    */
    @@ -127,6 +102,37 @@ struct x25_dte_facilities {
    __u8 called_ae[20];
    };

    +/*
    + * DTE/DCE subscription options.
    + *
    + * As this is missing lots of options, user should expect major
    + * changes of this structure in 2.5.x which might break compatibility.
    + * The somewhat ugly dimension 200-sizeof() is needed to maintain
    + * backward compatibility.
    + */
    +struct x25_subscrip_struct {
    + char device[200 - ((2 * sizeof(unsigned long)) +
    + sizeof(struct x25_facilities) +
    + (2 * sizeof(unsigned int)))];
    + unsigned int dce;
    + unsigned int lc;
    + struct x25_facilities facilities;
    + unsigned long t20;
    + unsigned long global_facil_mask; /* 0 to disable negotiation */
    + unsigned int extended;
    +};
    +
    +/* values for above global_facil_mask */
    +
    +#define X25_MASK_REVERSE 0x01
    +#define X25_MASK_THROUGHPUT 0x02
    +#define X25_MASK_PACKET_SIZE 0x04
    +#define X25_MASK_WINDOW_SIZE 0x08
    +
    +#define X25_MASK_CALLING_AE 0x10
    +#define X25_MASK_CALLED_AE 0x20
    +
    +
    /*
    * Call User Data structure.
    */
    diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
    index d2a52c254cca..4c2a395fdbdb 100644
    --- a/net/x25/af_x25.c
    +++ b/net/x25/af_x25.c
    @@ -72,8 +72,21 @@ static const struct proto_ops x25_proto_ops;
    static const struct x25_address null_x25_address = {" "};

    #ifdef CONFIG_COMPAT
    +struct compat_x25_facilities {
    + compat_uint_t winsize_in, winsize_out;
    + compat_uint_t pacsize_in, pacsize_out;
    + compat_uint_t throughput;
    + compat_uint_t reverse;
    +};
    +
    struct compat_x25_subscrip_struct {
    - char device[200-sizeof(compat_ulong_t)];
    + char device[200 - ((2 * sizeof(compat_ulong_t)) +
    + sizeof(struct compat_x25_facilities) +
    + (2 * sizeof(compat_uint_t)))];
    + compat_uint_t dce;
    + compat_uint_t lc;
    + struct compat_x25_facilities facilities;
    + compat_ulong_t t20;
    compat_ulong_t global_facil_mask;
    compat_uint_t extended;
    };
    @@ -373,13 +386,26 @@ static unsigned int x25_new_lci(struct x25_neigh *nb)
    unsigned int lci = 1;
    struct sock *sk;

    - while ((sk = x25_find_socket(lci, nb)) != NULL) {
    - sock_put(sk);
    - if (++lci == 4096) {
    - lci = 0;
    - break;
    + if (nb->dce) {
    + while ((sk = x25_find_socket(lci, nb)) != NULL) {
    + sock_put(sk);
    + if (++lci > nb->lc) {
    + lci = 0;
    + break;
    + }
    + cond_resched();
    + }
    + } else {
    + lci = nb->lc;
    +
    + while ((sk = x25_find_socket(lci, nb)) != NULL) {
    + sock_put(sk);
    + if (--lci == 0) {
    + lci = 0;
    + break;
    + }
    + cond_resched();
    }
    - cond_resched();
    }

    return lci;
    @@ -813,6 +839,10 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
    if (!x25->neighbour)
    goto out_put_route;

    + if (!x25->socket_defined_facilities)
    + memcpy(&x25->facilities, &x25->neighbour->facilities,
    + sizeof(struct x25_facilities));
    +
    x25_limit_facilities(&x25->facilities, x25->neighbour);

    x25->lci = x25_new_lci(x25->neighbour);
    @@ -1046,7 +1076,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
    /*
    * Try to reach a compromise on the requested facilities.
    */
    - len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities);
    + len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities, nb);
    if (len == -1)
    goto out_sock_put;

    @@ -1460,10 +1490,15 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
    rc = x25_subscr_ioctl(cmd, argp);
    break;
    case SIOCX25GFACILITIES: {
    + rc = -EINVAL;
    lock_sock(sk);
    + if (sk->sk_state != TCP_ESTABLISHED &&
    + !x25->socket_defined_facilities)
    + goto out_gfac_release;
    rc = copy_to_user(argp, &x25->facilities,
    sizeof(x25->facilities))
    ? -EFAULT : 0;
    +out_gfac_release:
    release_sock(sk);
    break;
    }
    @@ -1477,16 +1512,16 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
    lock_sock(sk);
    if (sk->sk_state != TCP_LISTEN &&
    sk->sk_state != TCP_CLOSE)
    - goto out_fac_release;
    + goto out_sfac_release;
    if (facilities.pacsize_in < X25_PS16 ||
    facilities.pacsize_in > X25_PS4096)
    - goto out_fac_release;
    + goto out_sfac_release;
    if (facilities.pacsize_out < X25_PS16 ||
    facilities.pacsize_out > X25_PS4096)
    - goto out_fac_release;
    + goto out_sfac_release;
    if (facilities.winsize_in < 1 ||
    facilities.winsize_in > 127)
    - goto out_fac_release;
    + goto out_sfac_release;
    if (facilities.throughput) {
    int out = facilities.throughput & 0xf0;
    int in = facilities.throughput & 0x0f;
    @@ -1494,19 +1529,20 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
    facilities.throughput |=
    X25_DEFAULT_THROUGHPUT << 4;
    else if (out < 0x30 || out > 0xD0)
    - goto out_fac_release;
    + goto out_sfac_release;
    if (!in)
    facilities.throughput |=
    X25_DEFAULT_THROUGHPUT;
    else if (in < 0x03 || in > 0x0D)
    - goto out_fac_release;
    + goto out_sfac_release;
    }
    if (facilities.reverse &&
    (facilities.reverse & 0x81) != 0x81)
    - goto out_fac_release;
    + goto out_sfac_release;
    x25->facilities = facilities;
    + x25->socket_defined_facilities = 1;
    rc = 0;
    -out_fac_release:
    +out_sfac_release:
    release_sock(sk);
    break;
    }
    @@ -1658,6 +1694,9 @@ static int compat_x25_subscr_ioctl(unsigned int cmd,
    struct net_device *dev;
    int rc = -EINVAL;

    + if (cmd != SIOCX25GSUBSCRIP && cmd != SIOCX25SSUBSCRIP)
    + goto out;
    +
    rc = -EFAULT;
    if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32)))
    goto out;
    @@ -1671,28 +1710,86 @@ static int compat_x25_subscr_ioctl(unsigned int cmd,
    if (nb == NULL)
    goto out_dev_put;

    - dev_put(dev);
    -
    if (cmd == SIOCX25GSUBSCRIP) {
    read_lock_bh(&x25_neigh_list_lock);
    x25_subscr.extended = nb->extended;
    + x25_subscr.dce = nb->dce;
    + x25_subscr.lc = nb->lc;
    + x25_subscr.facilities.winsize_in = nb->facilities.winsize_in;
    + x25_subscr.facilities.winsize_out = nb->facilities.winsize_out;
    + x25_subscr.facilities.pacsize_in = nb->facilities.pacsize_in;
    + x25_subscr.facilities.pacsize_out = nb->facilities.pacsize_out;
    + x25_subscr.facilities.throughput = nb->facilities.throughput;
    + x25_subscr.facilities.reverse = nb->facilities.reverse;
    + x25_subscr.t20 = nb->t20;
    x25_subscr.global_facil_mask = nb->global_facil_mask;
    read_unlock_bh(&x25_neigh_list_lock);
    rc = copy_to_user(x25_subscr32, &x25_subscr,
    sizeof(*x25_subscr32)) ? -EFAULT : 0;
    } else {
    rc = -EINVAL;
    - if (x25_subscr.extended == 0 || x25_subscr.extended == 1) {
    - rc = 0;
    - write_lock_bh(&x25_neigh_list_lock);
    - nb->extended = x25_subscr.extended;
    - nb->global_facil_mask = x25_subscr.global_facil_mask;
    - write_unlock_bh(&x25_neigh_list_lock);
    +
    + if (dev->flags & IFF_UP)
    + return -EBUSY;
    +
    + if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.dce != 0 && x25_subscr.dce != 1)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.lc < 1 || x25_subscr.lc > 4095)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.facilities.pacsize_in < X25_PS16 ||
    + x25_subscr.facilities.pacsize_in > X25_PS4096)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.facilities.pacsize_out < X25_PS16 ||
    + x25_subscr.facilities.pacsize_out > X25_PS4096)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.facilities.winsize_in < 1 ||
    + x25_subscr.facilities.winsize_in > 127)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.facilities.throughput) {
    + int out = x25_subscr.facilities.throughput & 0xf0;
    + int in = x25_subscr.facilities.throughput & 0x0f;
    +
    + if (!out)
    + x25_subscr.facilities.throughput |=
    + X25_DEFAULT_THROUGHPUT << 4;
    + else if (out < 0x30 || out > 0xD0)
    + goto out_dev_and_neigh_put;
    + if (!in)
    + x25_subscr.facilities.throughput |=
    + X25_DEFAULT_THROUGHPUT;
    + else if (in < 0x03 || in > 0x0D)
    + goto out_dev_and_neigh_put;
    }
    + if (x25_subscr.facilities.reverse &&
    + (x25_subscr.facilities.reverse & 0x81) != 0x81)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.t20 < 1 * HZ || x25_subscr.t20 > 300 * HZ)
    + goto out_dev_and_neigh_put;
    +
    + rc = 0;
    + write_lock_bh(&x25_neigh_list_lock);
    + nb->extended = x25_subscr.extended;
    + nb->dce = x25_subscr.dce;
    + nb->lc = x25_subscr.lc;
    + nb->facilities.winsize_in = x25_subscr.facilities.winsize_in;
    + nb->facilities.winsize_out = x25_subscr.facilities.winsize_out;
    + nb->facilities.pacsize_in = x25_subscr.facilities.pacsize_in;
    + nb->facilities.pacsize_out = x25_subscr.facilities.pacsize_out;
    + nb->facilities.throughput = x25_subscr.facilities.throughput;
    + nb->facilities.reverse = x25_subscr.facilities.reverse;
    + nb->t20 = x25_subscr.t20;
    + nb->global_facil_mask = x25_subscr.global_facil_mask;
    + write_unlock_bh(&x25_neigh_list_lock);
    }
    + dev_put(dev);
    +
    x25_neigh_put(nb);
    out:
    return rc;
    +out_dev_and_neigh_put:
    + x25_neigh_put(nb);
    out_dev_put:
    dev_put(dev);
    goto out;
    diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
    index 8e1a49b0c0dc..e6c9f9376206 100644
    --- a/net/x25/x25_facilities.c
    +++ b/net/x25/x25_facilities.c
    @@ -263,13 +263,17 @@ int x25_create_facilities(unsigned char *buffer,
    * The only real problem is with reverse charging.
    */
    int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
    - struct x25_facilities *new, struct x25_dte_facilities *dte)
    + struct x25_facilities *new, struct x25_dte_facilities *dte,
    + struct x25_neigh *nb)
    {
    struct x25_sock *x25 = x25_sk(sk);
    struct x25_facilities *ours = &x25->facilities;
    struct x25_facilities theirs;
    int len;

    + if (!x25->socket_defined_facilities)
    + ours = &nb->facilities;
    +
    memset(&theirs, 0, sizeof(theirs));
    memcpy(new, ours, sizeof(*new));
    memset(dte, 0, sizeof(*dte));
    diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
    index 92828a8a4ada..2af50d585b4b 100644
    --- a/net/x25/x25_link.c
    +++ b/net/x25/x25_link.c
    @@ -125,8 +125,16 @@ static void x25_transmit_restart_request(struct x25_neigh *nb)
    *dptr++ = nb->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
    *dptr++ = 0x00;
    *dptr++ = X25_RESTART_REQUEST;
    - *dptr++ = 0x00;
    - *dptr++ = 0;
    +
    + *dptr = 0x00; /* cause */
    +
    + /* set bit 8, if DTE and cause != 0x00 */
    + if (!nb->dce && *dptr != 0x00)
    + *dptr |= (unsigned char)0x80;
    +
    + dptr++;
    +
    + *dptr++ = 0x00; /* diagnostic */

    skb->sk = NULL;

    @@ -181,8 +189,16 @@ void x25_transmit_clear_request(struct x25_neigh *nb, unsigned int lci,
    X25_GFI_STDSEQ);
    *dptr++ = (lci >> 0) & 0xFF;
    *dptr++ = X25_CLEAR_REQUEST;
    - *dptr++ = cause;
    - *dptr++ = 0x00;
    +
    + *dptr = cause; /* cause */
    +
    + /* set bit 8, if DTE and cause != 0x00 */
    + if (!nb->dce && *dptr != 0x00)
    + *dptr |= (unsigned char)0x80;
    +
    + dptr++;
    +
    + *dptr++ = 0x00; /* diagnostic */

    skb->sk = NULL;

    @@ -261,6 +277,15 @@ void x25_link_device_add(struct net_device *dev)
    nb->dev = dev;
    nb->state = X25_LINK_STATE_0;
    nb->extended = 0;
    + nb->dce = 0;
    + nb->lc = 10;
    + nb->facilities.winsize_in = X25_DEFAULT_WINDOW_SIZE;
    + nb->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
    + nb->facilities.pacsize_in = X25_DEFAULT_PACKET_SIZE;
    + nb->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
    + /* by default don't negotiate throughput */
    + nb->facilities.throughput = 0;
    + nb->facilities.reverse = X25_DEFAULT_REVERSE;
    /*
    * Enables negotiation
    */
    @@ -389,28 +414,76 @@ int x25_subscr_ioctl(unsigned int cmd, void __user *arg)
    if ((nb = x25_get_neigh(dev)) == NULL)
    goto out_dev_put;

    - dev_put(dev);
    -
    if (cmd == SIOCX25GSUBSCRIP) {
    read_lock_bh(&x25_neigh_list_lock);
    x25_subscr.extended = nb->extended;
    + x25_subscr.dce = nb->dce;
    + x25_subscr.lc = nb->lc;
    + x25_subscr.facilities = nb->facilities;
    + x25_subscr.t20 = nb->t20;
    x25_subscr.global_facil_mask = nb->global_facil_mask;
    read_unlock_bh(&x25_neigh_list_lock);
    rc = copy_to_user(arg, &x25_subscr,
    sizeof(x25_subscr)) ? -EFAULT : 0;
    } else {
    rc = -EINVAL;
    - if (!(x25_subscr.extended && x25_subscr.extended != 1)) {
    - rc = 0;
    - write_lock_bh(&x25_neigh_list_lock);
    - nb->extended = x25_subscr.extended;
    - nb->global_facil_mask = x25_subscr.global_facil_mask;
    - write_unlock_bh(&x25_neigh_list_lock);
    +
    + if (dev->flags & IFF_UP)
    + return -EBUSY;
    +
    + if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.dce != 0 && x25_subscr.dce != 1)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.lc < 1 || x25_subscr.lc > 4095)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.facilities.pacsize_in < X25_PS16 ||
    + x25_subscr.facilities.pacsize_in > X25_PS4096)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.facilities.pacsize_out < X25_PS16 ||
    + x25_subscr.facilities.pacsize_out > X25_PS4096)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.facilities.winsize_in < 1 ||
    + x25_subscr.facilities.winsize_in > 127)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.facilities.throughput) {
    + int out = x25_subscr.facilities.throughput & 0xf0;
    + int in = x25_subscr.facilities.throughput & 0x0f;
    +
    + if (!out)
    + x25_subscr.facilities.throughput |=
    + X25_DEFAULT_THROUGHPUT << 4;
    + else if (out < 0x30 || out > 0xD0)
    + goto out_dev_and_neigh_put;
    + if (!in)
    + x25_subscr.facilities.throughput |=
    + X25_DEFAULT_THROUGHPUT;
    + else if (in < 0x03 || in > 0x0D)
    + goto out_dev_and_neigh_put;
    }
    + if (x25_subscr.facilities.reverse &&
    + (x25_subscr.facilities.reverse & 0x81) != 0x81)
    + goto out_dev_and_neigh_put;
    + if (x25_subscr.t20 < 1 * HZ || x25_subscr.t20 > 300 * HZ)
    + goto out_dev_and_neigh_put;
    +
    + rc = 0;
    + write_lock_bh(&x25_neigh_list_lock);
    + nb->extended = x25_subscr.extended;
    + nb->dce = x25_subscr.dce;
    + nb->lc = x25_subscr.lc;
    + nb->facilities = x25_subscr.facilities;
    + nb->t20 = x25_subscr.t20;
    + nb->global_facil_mask = x25_subscr.global_facil_mask;
    + write_unlock_bh(&x25_neigh_list_lock);
    }
    + dev_put(dev);
    +
    x25_neigh_put(nb);
    out:
    return rc;
    +out_dev_and_neigh_put:
    + x25_neigh_put(nb);
    out_dev_put:
    dev_put(dev);
    goto out;
    diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
    index 0285aaa1e93c..c195d1c89ad7 100644
    --- a/net/x25/x25_subr.c
    +++ b/net/x25/x25_subr.c
    @@ -218,15 +218,31 @@ void x25_write_internal(struct sock *sk, int frametype)
    case X25_CLEAR_REQUEST:
    dptr = skb_put(skb, 3);
    *dptr++ = frametype;
    - *dptr++ = x25->causediag.cause;
    +
    + *dptr = x25->causediag.cause;
    +
    + /* set bit 8, if DTE and cause != 0x00 */
    + if (!x25->neighbour->dce && *dptr != 0x00)
    + *dptr |= (unsigned char)0x80;
    +
    + dptr++;
    +
    *dptr++ = x25->causediag.diagnostic;
    break;

    case X25_RESET_REQUEST:
    dptr = skb_put(skb, 3);
    *dptr++ = frametype;
    - *dptr++ = 0x00; /* XXX */
    - *dptr++ = 0x00; /* XXX */
    +
    + *dptr = 0x00; /* cause */
    +
    + /* set bit 8, if DTE and cause != 0x00 */
    + if (!x25->neighbour->dce && *dptr != 0x00)
    + *dptr |= (unsigned char)0x80;
    +
    + dptr++;
    +
    + *dptr++ = 0x00; /* diagnostic */
    break;

    case X25_RR:
    --
    2.20.1
    \
     
     \ /
      Last update: 2020-11-16 14:59    [W:4.156 / U:0.044 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site