/* * Take the default packet length for the device if zero is * specified.
*/ if (paclen == 0) {
rcu_read_lock();
ax25_dev = ax25_dev_ax25dev(dev); if (!ax25_dev) {
rcu_read_unlock(); return NULL;
}
paclen = ax25_dev->values[AX25_VALUES_PACLEN];
rcu_read_unlock();
}
/* * Look for an existing connection.
*/ if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) {
ax25_output(ax25, paclen, skb); return ax25; /* It already existed */
}
if (digi != NULL) {
ax25->digipeat = kmemdup(digi, sizeof(*digi), GFP_ATOMIC); if (ax25->digipeat == NULL) {
ax25_cb_put(ax25); return NULL;
}
}
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_std_establish_data_link(ax25); break;
#ifdef CONFIG_AX25_DAMA_SLAVE case AX25_PROTO_DAMA_SLAVE: if (ax25_dev->dama.slave)
ax25_ds_establish_data_link(ax25); else
ax25_std_establish_data_link(ax25); break; #endif
}
/* * There is one ref for the state machine; a caller needs * one more to put it back, just like with the existing one.
*/
ax25_cb_hold(ax25);
ax25_cb_add(ax25);
ax25->state = AX25_STATE_1;
ax25_start_heartbeat(ax25);
ax25_output(ax25, paclen, skb);
return ax25; /* We had to create it */
}
EXPORT_SYMBOL(ax25_send_frame);
/* * All outgoing AX.25 I frames pass via this routine. Therefore this is * where the fragmentation of frames takes place. If fragment is set to * zero then we are not allowed to do fragmentation, even if the frame * is too large.
*/ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
{ struct sk_buff *skbn; unsignedchar *p; int frontlen, len, fragno, ka9qfrag, first = 1;
if (paclen < 16) {
WARN_ON_ONCE(1);
kfree_skb(skb); return;
}
if ((skb->len - 1) > paclen) { if (*skb->data == AX25_P_TEXT) {
skb_pull(skb, 1); /* skip PID */
ka9qfrag = 0;
} else {
paclen -= 2; /* Allow for fragment control info */
ka9qfrag = 1;
}
skb_pull(skb, len);
skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
}
kfree_skb(skb);
} else {
skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */
}
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_kick(ax25); break;
#ifdef CONFIG_AX25_DAMA_SLAVE /* * A DAMA slave is _required_ to work as normal AX.25L2V2 * if no DAMA master is available.
*/ case AX25_PROTO_DAMA_SLAVE: if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25); break; #endif
}
}
/* * This procedure is passed a buffer descriptor for an iframe. It builds * the rest of the control part of the frame and then writes it out.
*/ staticvoid ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
{ unsignedchar *frame;
if (skb == NULL) return;
skb_reset_network_header(skb);
if (ax25->modulus == AX25_MODULUS) {
frame = skb_push(skb, 1);
/* * Transmit data until either we're out of data to send or * the window is full. Send a poll on the final I frame if * the window is filled.
*/
/* * Dequeue the frame and copy it. * Check for race with ax25_clear_queues().
*/
skb = skb_dequeue(&ax25->write_queue); if (!skb) return;
ax25->vs = start;
do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
skb_queue_head(&ax25->write_queue, skb); break;
}
if (skb->sk != NULL)
skb_set_owner_w(skbn, skb->sk);
next = (ax25->vs + 1) % ax25->modulus;
last = (next == end);
/* * Transmit the frame copy. * bke 960114: do not set the Poll bit on the last frame * in DAMA mode.
*/ switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF); break;
#ifdef CONFIG_AX25_DAMA_SLAVE case AX25_PROTO_DAMA_SLAVE:
ax25_send_iframe(ax25, skbn, AX25_POLLOFF); break; #endif
}
ax25->vs = next;
/* * Requeue the original data frame.
*/
skb_queue_tail(&ax25->ack_queue, skb);
} while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
ax25->condition &= ~AX25_COND_ACK_PENDING;
if (!ax25_t1timer_running(ax25)) {
ax25_stop_t3timer(ax25);
ax25_calculate_t1(ax25);
ax25_start_t1timer(ax25);
}
}
void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
{ unsignedchar *ptr; int headroom;
if (ax25->ax25_dev == NULL) {
ax25_disconnect(ax25, ENETUNREACH); return;
}
headroom = ax25_addr_size(ax25->digipeat);
if (unlikely(skb_headroom(skb) < headroom)) {
skb = skb_expand_head(skb, headroom); if (!skb) {
printk(KERN_CRIT "AX.25: ax25_transmit_buffer - out of memory\n"); return;
}
}
/* * A small shim to dev_queue_xmit to add the KISS control byte, and do * any packet forwarding in operation.
*/ void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev)
{ unsignedchar *ptr;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.