linux/net/ax25/ax25_ip.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 *
   7 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
   8 */
   9#include <linux/errno.h>
  10#include <linux/types.h>
  11#include <linux/socket.h>
  12#include <linux/in.h>
  13#include <linux/kernel.h>
  14#include <linux/module.h>
  15#include <linux/timer.h>
  16#include <linux/string.h>
  17#include <linux/sockios.h>
  18#include <linux/net.h>
  19#include <linux/slab.h>
  20#include <net/ax25.h>
  21#include <linux/inet.h>
  22#include <linux/netdevice.h>
  23#include <linux/if_arp.h>
  24#include <linux/skbuff.h>
  25#include <net/sock.h>
  26#include <asm/uaccess.h>
  27#include <linux/fcntl.h>
  28#include <linux/termios.h>      /* For TIOCINQ/OUTQ */
  29#include <linux/mm.h>
  30#include <linux/interrupt.h>
  31#include <linux/notifier.h>
  32#include <linux/proc_fs.h>
  33#include <linux/stat.h>
  34#include <linux/sysctl.h>
  35#include <net/ip.h>
  36#include <net/arp.h>
  37
  38/*
  39 *      IP over AX.25 encapsulation.
  40 */
  41
  42/*
  43 *      Shove an AX.25 UI header on an IP packet and handle ARP
  44 */
  45
  46#ifdef CONFIG_INET
  47
  48static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
  49                            unsigned short type, const void *daddr,
  50                            const void *saddr, unsigned int len)
  51{
  52        unsigned char *buff;
  53
  54        /* they sometimes come back to us... */
  55        if (type == ETH_P_AX25)
  56                return 0;
  57
  58        /* header is an AX.25 UI frame from us to them */
  59        buff = skb_push(skb, AX25_HEADER_LEN);
  60        *buff++ = 0x00; /* KISS DATA */
  61
  62        if (daddr != NULL)
  63                memcpy(buff, daddr, dev->addr_len);     /* Address specified */
  64
  65        buff[6] &= ~AX25_CBIT;
  66        buff[6] &= ~AX25_EBIT;
  67        buff[6] |= AX25_SSSID_SPARE;
  68        buff    += AX25_ADDR_LEN;
  69
  70        if (saddr != NULL)
  71                memcpy(buff, saddr, dev->addr_len);
  72        else
  73                memcpy(buff, dev->dev_addr, dev->addr_len);
  74
  75        buff[6] &= ~AX25_CBIT;
  76        buff[6] |= AX25_EBIT;
  77        buff[6] |= AX25_SSSID_SPARE;
  78        buff    += AX25_ADDR_LEN;
  79
  80        *buff++  = AX25_UI;     /* UI */
  81
  82        /* Append a suitable AX.25 PID */
  83        switch (type) {
  84        case ETH_P_IP:
  85                *buff++ = AX25_P_IP;
  86                break;
  87        case ETH_P_ARP:
  88                *buff++ = AX25_P_ARP;
  89                break;
  90        default:
  91                printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type);
  92                *buff++ = 0;
  93                break;
  94        }
  95
  96        if (daddr != NULL)
  97                return AX25_HEADER_LEN;
  98
  99        return -AX25_HEADER_LEN;        /* Unfinished header */
 100}
 101
 102netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
 103{
 104        struct sk_buff *ourskb;
 105        unsigned char *bp  = skb->data;
 106        ax25_route *route;
 107        struct net_device *dev = NULL;
 108        ax25_address *src, *dst;
 109        ax25_digi *digipeat = NULL;
 110        ax25_dev *ax25_dev;
 111        ax25_cb *ax25;
 112        char ip_mode = ' ';
 113
 114        dst = (ax25_address *)(bp + 1);
 115        src = (ax25_address *)(bp + 8);
 116
 117        route = ax25_get_route(dst, NULL);
 118        if (route) {
 119                digipeat = route->digipeat;
 120                dev = route->dev;
 121                ip_mode = route->ip_mode;
 122        }
 123
 124        if (dev == NULL)
 125                dev = skb->dev;
 126
 127        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
 128                kfree_skb(skb);
 129                goto put;
 130        }
 131
 132        if (bp[16] == AX25_P_IP) {
 133                if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
 134                        /*
 135                         *      We copy the buffer and release the original thereby
 136                         *      keeping it straight
 137                         *
 138                         *      Note: we report 1 back so the caller will
 139                         *      not feed the frame direct to the physical device
 140                         *      We don't want that to happen. (It won't be upset
 141                         *      as we have pulled the frame from the queue by
 142                         *      freeing it).
 143                         *
 144                         *      NB: TCP modifies buffers that are still
 145                         *      on a device queue, thus we use skb_copy()
 146                         *      instead of using skb_clone() unless this
 147                         *      gets fixed.
 148                         */
 149
 150                        ax25_address src_c;
 151                        ax25_address dst_c;
 152
 153                        if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
 154                                kfree_skb(skb);
 155                                goto put;
 156                        }
 157
 158                        if (skb->sk != NULL)
 159                                skb_set_owner_w(ourskb, skb->sk);
 160
 161                        kfree_skb(skb);
 162                        /* dl9sau: bugfix
 163                         * after kfree_skb(), dst and src which were pointer
 164                         * to bp which is part of skb->data would not be valid
 165                         * anymore hope that after skb_pull(ourskb, ..) our
 166                         * dsc_c and src_c will not become invalid
 167                         */
 168                        bp  = ourskb->data;
 169                        dst_c = *(ax25_address *)(bp + 1);
 170                        src_c = *(ax25_address *)(bp + 8);
 171
 172                        skb_pull(ourskb, AX25_HEADER_LEN - 1);  /* Keep PID */
 173                        skb_reset_network_header(ourskb);
 174
 175                        ax25=ax25_send_frame(
 176                            ourskb,
 177                            ax25_dev->values[AX25_VALUES_PACLEN],
 178                            &src_c,
 179                            &dst_c, digipeat, dev);
 180                        if (ax25) {
 181                                ax25_cb_put(ax25);
 182                        }
 183                        goto put;
 184                }
 185        }
 186
 187        bp[7]  &= ~AX25_CBIT;
 188        bp[7]  &= ~AX25_EBIT;
 189        bp[7]  |= AX25_SSSID_SPARE;
 190
 191        bp[14] &= ~AX25_CBIT;
 192        bp[14] |= AX25_EBIT;
 193        bp[14] |= AX25_SSSID_SPARE;
 194
 195        skb_pull(skb, AX25_KISS_HEADER_LEN);
 196
 197        if (digipeat != NULL) {
 198                if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
 199                        kfree_skb(skb);
 200                        goto put;
 201                }
 202
 203                skb = ourskb;
 204        }
 205
 206        ax25_queue_xmit(skb, dev);
 207
 208put:
 209        if (route)
 210                ax25_put_route(route);
 211
 212        return NETDEV_TX_OK;
 213}
 214
 215#else   /* INET */
 216
 217static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
 218                            unsigned short type, const void *daddr,
 219                            const void *saddr, unsigned int len)
 220{
 221        return -AX25_HEADER_LEN;
 222}
 223
 224netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
 225{
 226        kfree_skb(skb);
 227        return NETDEV_TX_OK;
 228}
 229#endif
 230
 231static bool ax25_validate_header(const char *header, unsigned int len)
 232{
 233        ax25_digi digi;
 234
 235        if (!len)
 236                return false;
 237
 238        if (header[0])
 239                return true;
 240
 241        return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
 242                               NULL);
 243}
 244
 245const struct header_ops ax25_header_ops = {
 246        .create = ax25_hard_header,
 247        .validate = ax25_validate_header,
 248};
 249
 250EXPORT_SYMBOL(ax25_header_ops);
 251EXPORT_SYMBOL(ax25_ip_xmit);
 252
 253