18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) 58c2ecf20Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 68c2ecf20Sopenharmony_ci * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/errno.h> 98c2ecf20Sopenharmony_ci#include <linux/types.h> 108c2ecf20Sopenharmony_ci#include <linux/socket.h> 118c2ecf20Sopenharmony_ci#include <linux/in.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/timer.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/sockios.h> 178c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 188c2ecf20Sopenharmony_ci#include <linux/net.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <net/ax25.h> 218c2ecf20Sopenharmony_ci#include <linux/inet.h> 228c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 248c2ecf20Sopenharmony_ci#include <net/sock.h> 258c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 268c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 278c2ecf20Sopenharmony_ci#include <linux/mm.h> 288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(ax25_frag_lock); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci ax25_dev *ax25_dev; 358c2ecf20Sopenharmony_ci ax25_cb *ax25; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci /* 388c2ecf20Sopenharmony_ci * Take the default packet length for the device if zero is 398c2ecf20Sopenharmony_ci * specified. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci if (paclen == 0) { 428c2ecf20Sopenharmony_ci if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) 438c2ecf20Sopenharmony_ci return NULL; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci paclen = ax25_dev->values[AX25_VALUES_PACLEN]; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * Look for an existing connection. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) { 528c2ecf20Sopenharmony_ci ax25_output(ax25, paclen, skb); 538c2ecf20Sopenharmony_ci return ax25; /* It already existed */ 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) 578c2ecf20Sopenharmony_ci return NULL; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if ((ax25 = ax25_create_cb()) == NULL) 608c2ecf20Sopenharmony_ci return NULL; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci ax25_fillin_cb(ax25, ax25_dev); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci ax25->source_addr = *src; 658c2ecf20Sopenharmony_ci ax25->dest_addr = *dest; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (digi != NULL) { 688c2ecf20Sopenharmony_ci ax25->digipeat = kmemdup(digi, sizeof(*digi), GFP_ATOMIC); 698c2ecf20Sopenharmony_ci if (ax25->digipeat == NULL) { 708c2ecf20Sopenharmony_ci ax25_cb_put(ax25); 718c2ecf20Sopenharmony_ci return NULL; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { 768c2ecf20Sopenharmony_ci case AX25_PROTO_STD_SIMPLEX: 778c2ecf20Sopenharmony_ci case AX25_PROTO_STD_DUPLEX: 788c2ecf20Sopenharmony_ci ax25_std_establish_data_link(ax25); 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#ifdef CONFIG_AX25_DAMA_SLAVE 828c2ecf20Sopenharmony_ci case AX25_PROTO_DAMA_SLAVE: 838c2ecf20Sopenharmony_ci if (ax25_dev->dama.slave) 848c2ecf20Sopenharmony_ci ax25_ds_establish_data_link(ax25); 858c2ecf20Sopenharmony_ci else 868c2ecf20Sopenharmony_ci ax25_std_establish_data_link(ax25); 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci#endif 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * There is one ref for the state machine; a caller needs 938c2ecf20Sopenharmony_ci * one more to put it back, just like with the existing one. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci ax25_cb_hold(ax25); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci ax25_cb_add(ax25); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci ax25->state = AX25_STATE_1; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ax25_start_heartbeat(ax25); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci ax25_output(ax25, paclen, skb); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return ax25; /* We had to create it */ 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ax25_send_frame); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* 1118c2ecf20Sopenharmony_ci * All outgoing AX.25 I frames pass via this routine. Therefore this is 1128c2ecf20Sopenharmony_ci * where the fragmentation of frames takes place. If fragment is set to 1138c2ecf20Sopenharmony_ci * zero then we are not allowed to do fragmentation, even if the frame 1148c2ecf20Sopenharmony_ci * is too large. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_civoid ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct sk_buff *skbn; 1198c2ecf20Sopenharmony_ci unsigned char *p; 1208c2ecf20Sopenharmony_ci int frontlen, len, fragno, ka9qfrag, first = 1; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (paclen < 16) { 1238c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 1248c2ecf20Sopenharmony_ci kfree_skb(skb); 1258c2ecf20Sopenharmony_ci return; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if ((skb->len - 1) > paclen) { 1298c2ecf20Sopenharmony_ci if (*skb->data == AX25_P_TEXT) { 1308c2ecf20Sopenharmony_ci skb_pull(skb, 1); /* skip PID */ 1318c2ecf20Sopenharmony_ci ka9qfrag = 0; 1328c2ecf20Sopenharmony_ci } else { 1338c2ecf20Sopenharmony_ci paclen -= 2; /* Allow for fragment control info */ 1348c2ecf20Sopenharmony_ci ka9qfrag = 1; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci fragno = skb->len / paclen; 1388c2ecf20Sopenharmony_ci if (skb->len % paclen == 0) fragno--; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci frontlen = skb_headroom(skb); /* Address space + CTRL */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci while (skb->len > 0) { 1438c2ecf20Sopenharmony_ci spin_lock_bh(&ax25_frag_lock); 1448c2ecf20Sopenharmony_ci if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) { 1458c2ecf20Sopenharmony_ci spin_unlock_bh(&ax25_frag_lock); 1468c2ecf20Sopenharmony_ci printk(KERN_CRIT "AX.25: ax25_output - out of memory\n"); 1478c2ecf20Sopenharmony_ci return; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (skb->sk != NULL) 1518c2ecf20Sopenharmony_ci skb_set_owner_w(skbn, skb->sk); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci spin_unlock_bh(&ax25_frag_lock); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci len = (paclen > skb->len) ? skb->len : paclen; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (ka9qfrag == 1) { 1588c2ecf20Sopenharmony_ci skb_reserve(skbn, frontlen + 2); 1598c2ecf20Sopenharmony_ci skb_set_network_header(skbn, 1608c2ecf20Sopenharmony_ci skb_network_offset(skb)); 1618c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, skb_put(skbn, len), len); 1628c2ecf20Sopenharmony_ci p = skb_push(skbn, 2); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci *p++ = AX25_P_SEGMENT; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci *p = fragno--; 1678c2ecf20Sopenharmony_ci if (first) { 1688c2ecf20Sopenharmony_ci *p |= AX25_SEG_FIRST; 1698c2ecf20Sopenharmony_ci first = 0; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci } else { 1728c2ecf20Sopenharmony_ci skb_reserve(skbn, frontlen + 1); 1738c2ecf20Sopenharmony_ci skb_set_network_header(skbn, 1748c2ecf20Sopenharmony_ci skb_network_offset(skb)); 1758c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, skb_put(skbn, len), len); 1768c2ecf20Sopenharmony_ci p = skb_push(skbn, 1); 1778c2ecf20Sopenharmony_ci *p = AX25_P_TEXT; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci skb_pull(skb, len); 1818c2ecf20Sopenharmony_ci skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */ 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci kfree_skb(skb); 1858c2ecf20Sopenharmony_ci } else { 1868c2ecf20Sopenharmony_ci skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */ 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { 1908c2ecf20Sopenharmony_ci case AX25_PROTO_STD_SIMPLEX: 1918c2ecf20Sopenharmony_ci case AX25_PROTO_STD_DUPLEX: 1928c2ecf20Sopenharmony_ci ax25_kick(ax25); 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#ifdef CONFIG_AX25_DAMA_SLAVE 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * A DAMA slave is _required_ to work as normal AX.25L2V2 1988c2ecf20Sopenharmony_ci * if no DAMA master is available. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci case AX25_PROTO_DAMA_SLAVE: 2018c2ecf20Sopenharmony_ci if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25); 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci#endif 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * This procedure is passed a buffer descriptor for an iframe. It builds 2098c2ecf20Sopenharmony_ci * the rest of the control part of the frame and then writes it out. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_cistatic void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci unsigned char *frame; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (skb == NULL) 2168c2ecf20Sopenharmony_ci return; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (ax25->modulus == AX25_MODULUS) { 2218c2ecf20Sopenharmony_ci frame = skb_push(skb, 1); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci *frame = AX25_I; 2248c2ecf20Sopenharmony_ci *frame |= (poll_bit) ? AX25_PF : 0; 2258c2ecf20Sopenharmony_ci *frame |= (ax25->vr << 5); 2268c2ecf20Sopenharmony_ci *frame |= (ax25->vs << 1); 2278c2ecf20Sopenharmony_ci } else { 2288c2ecf20Sopenharmony_ci frame = skb_push(skb, 2); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci frame[0] = AX25_I; 2318c2ecf20Sopenharmony_ci frame[0] |= (ax25->vs << 1); 2328c2ecf20Sopenharmony_ci frame[1] = (poll_bit) ? AX25_EPF : 0; 2338c2ecf20Sopenharmony_ci frame[1] |= (ax25->vr << 1); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci ax25_start_idletimer(ax25); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci ax25_transmit_buffer(ax25, skb, AX25_COMMAND); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_civoid ax25_kick(ax25_cb *ax25) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct sk_buff *skb, *skbn; 2448c2ecf20Sopenharmony_ci int last = 1; 2458c2ecf20Sopenharmony_ci unsigned short start, end, next; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4) 2488c2ecf20Sopenharmony_ci return; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (ax25->condition & AX25_COND_PEER_RX_BUSY) 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (skb_peek(&ax25->write_queue) == NULL) 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs; 2578c2ecf20Sopenharmony_ci end = (ax25->va + ax25->window) % ax25->modulus; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (start == end) 2608c2ecf20Sopenharmony_ci return; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* 2638c2ecf20Sopenharmony_ci * Transmit data until either we're out of data to send or 2648c2ecf20Sopenharmony_ci * the window is full. Send a poll on the final I frame if 2658c2ecf20Sopenharmony_ci * the window is filled. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Dequeue the frame and copy it. 2708c2ecf20Sopenharmony_ci * Check for race with ax25_clear_queues(). 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci skb = skb_dequeue(&ax25->write_queue); 2738c2ecf20Sopenharmony_ci if (!skb) 2748c2ecf20Sopenharmony_ci return; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci ax25->vs = start; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci do { 2798c2ecf20Sopenharmony_ci if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { 2808c2ecf20Sopenharmony_ci skb_queue_head(&ax25->write_queue, skb); 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (skb->sk != NULL) 2858c2ecf20Sopenharmony_ci skb_set_owner_w(skbn, skb->sk); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci next = (ax25->vs + 1) % ax25->modulus; 2888c2ecf20Sopenharmony_ci last = (next == end); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Transmit the frame copy. 2928c2ecf20Sopenharmony_ci * bke 960114: do not set the Poll bit on the last frame 2938c2ecf20Sopenharmony_ci * in DAMA mode. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { 2968c2ecf20Sopenharmony_ci case AX25_PROTO_STD_SIMPLEX: 2978c2ecf20Sopenharmony_ci case AX25_PROTO_STD_DUPLEX: 2988c2ecf20Sopenharmony_ci ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF); 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci#ifdef CONFIG_AX25_DAMA_SLAVE 3028c2ecf20Sopenharmony_ci case AX25_PROTO_DAMA_SLAVE: 3038c2ecf20Sopenharmony_ci ax25_send_iframe(ax25, skbn, AX25_POLLOFF); 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci#endif 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci ax25->vs = next; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * Requeue the original data frame. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_ci skb_queue_tail(&ax25->ack_queue, skb); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ax25->condition &= ~AX25_COND_ACK_PENDING; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!ax25_t1timer_running(ax25)) { 3208c2ecf20Sopenharmony_ci ax25_stop_t3timer(ax25); 3218c2ecf20Sopenharmony_ci ax25_calculate_t1(ax25); 3228c2ecf20Sopenharmony_ci ax25_start_t1timer(ax25); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_civoid ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct sk_buff *skbn; 3298c2ecf20Sopenharmony_ci unsigned char *ptr; 3308c2ecf20Sopenharmony_ci int headroom; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (ax25->ax25_dev == NULL) { 3338c2ecf20Sopenharmony_ci ax25_disconnect(ax25, ENETUNREACH); 3348c2ecf20Sopenharmony_ci return; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci headroom = ax25_addr_size(ax25->digipeat); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (skb_headroom(skb) < headroom) { 3408c2ecf20Sopenharmony_ci if ((skbn = skb_realloc_headroom(skb, headroom)) == NULL) { 3418c2ecf20Sopenharmony_ci printk(KERN_CRIT "AX.25: ax25_transmit_buffer - out of memory\n"); 3428c2ecf20Sopenharmony_ci kfree_skb(skb); 3438c2ecf20Sopenharmony_ci return; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (skb->sk != NULL) 3478c2ecf20Sopenharmony_ci skb_set_owner_w(skbn, skb->sk); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci consume_skb(skb); 3508c2ecf20Sopenharmony_ci skb = skbn; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci ptr = skb_push(skb, headroom); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ax25_queue_xmit(skb, ax25->ax25_dev->dev); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/* 3618c2ecf20Sopenharmony_ci * A small shim to dev_queue_xmit to add the KISS control byte, and do 3628c2ecf20Sopenharmony_ci * any packet forwarding in operation. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_civoid ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci unsigned char *ptr; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci skb->protocol = ax25_type_trans(skb, ax25_fwd_dev(dev)); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ptr = skb_push(skb, 1); 3718c2ecf20Sopenharmony_ci *ptr = 0x00; /* KISS */ 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ciint ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci if (ax25->vs == nr) { 3798c2ecf20Sopenharmony_ci ax25_frames_acked(ax25, nr); 3808c2ecf20Sopenharmony_ci ax25_calculate_rtt(ax25); 3818c2ecf20Sopenharmony_ci ax25_stop_t1timer(ax25); 3828c2ecf20Sopenharmony_ci ax25_start_t3timer(ax25); 3838c2ecf20Sopenharmony_ci return 1; 3848c2ecf20Sopenharmony_ci } else { 3858c2ecf20Sopenharmony_ci if (ax25->va != nr) { 3868c2ecf20Sopenharmony_ci ax25_frames_acked(ax25, nr); 3878c2ecf20Sopenharmony_ci ax25_calculate_t1(ax25); 3888c2ecf20Sopenharmony_ci ax25_start_t1timer(ax25); 3898c2ecf20Sopenharmony_ci return 1; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci return 0; 3938c2ecf20Sopenharmony_ci} 394