Hi dag,
This is the result of my hacking on Ultra. I can have a ultra
message going from application to application (Yes, yes, yes !!!!), so
most of the plumbing is done (it's no longer a proof of concept)...
However, it's not finished yet. The receive path in af_irda
doesn't remove the header, and irlmp doesn't verify the upid. And also
it doesn't work when LAP is connected. And then there is the cleanups
and all the comments I left in the code...
Have fun...
Jean
diff -u -p linux/include/net/irda/irda.d1.h linux/include/net/irda/irda.h
--- linux/include/net/irda/irda.d1.h Wed Dec 8 10:59:10 1999
+++ linux/include/net/irda/irda.h Wed Dec 8 12:07:33 1999
@@ -116,8 +116,9 @@ struct irda_sock {
__u32 saddr; /* my local address */
__u32 daddr; /* peer address */
- struct lsap_cb *lsap; /* LSAP used by Ultra */
- __u8 pid; /* Protocol IP (PID) used by Ultra */
+ struct lsap_cb *lsap; /* LSAP (used by Ultra only) */
+ __u8 upid[4]; /* Ultra Protocol IP (UPID - used by Ultra) */
+ __u8 upid_l; /* Length of the UPID */
struct tsap_cb *tsap; /* TSAP used by this connection */
__u8 dtsap_sel; /* remote TSAP address */
diff -u -p linux/net/irda/af_irda.d1.c linux/net/irda/af_irda.c
--- linux/net/irda/af_irda.d1.c Wed Dec 8 11:01:08 1999
+++ linux/net/irda/af_irda.c Wed Dec 8 14:07:49 1999
@@ -75,7 +75,7 @@ static struct wait_queue *discovery_wait
#define IRDA_MAX_HEADER (TTP_MAX_HEADER)
#define ULTRA_MAX_DATA 382
-#define ULTRA_HEADER 1
+#define ULTRA_HEADER 4
/*
* Function irda_data_indication (instance, sap, skb)
@@ -426,7 +426,7 @@ static int irda_open_tsap(struct irda_so
* Open local Link Service Access Point (LSAP). Used for opening Ultra
* sockets
*/
-static int irda_open_lsap(struct irda_sock *self)
+static int irda_open_lsap(struct irda_sock *self, __u8 slsap_sel)
{
notify_t notify;
@@ -441,7 +441,7 @@ static int irda_open_lsap(struct irda_so
notify.instance = self;
strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME);
- self->lsap = irlmp_open_lsap(0x70, ¬ify);
+ self->lsap = irlmp_open_lsap(slsap_sel, ¬ify);
if (self->lsap == NULL) {
IRDA_DEBUG( 0, __FUNCTION__ "(), Unable to allocate LSAP!\n");
return -ENOMEM;
@@ -634,23 +634,12 @@ static int irda_bind(struct socket *sock
self = sk->protinfo.irda;
ASSERT(self != NULL, return -1;);
- if ((addr_len < sizeof(struct sockaddr_irda)) ||
- (addr_len > sizeof(struct sockaddr_irda)))
+ if (addr_len != sizeof(struct sockaddr_irda))
return -EINVAL;
/* Special care for Ultra sockets */
- if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA)) {
- err = irda_open_lsap(self);
- if (err < 0)
- return err;
-
- self->pid = addr->sir_lsap_sel;
-
- self->max_data_size = ULTRA_MAX_DATA - ULTRA_HEADER;
- self->max_header_size = IRDA_MAX_HEADER + ULTRA_HEADER;
-
- return 0;
- }
+ if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA))
+ return -ESOCKTNOSUPPORT;
err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name);
if (err < 0)
@@ -673,6 +662,90 @@ static int irda_bind(struct socket *sock
}
/*
+ * Function irda_bind_ultra (sock, uaddr, addr_len)
+ *
+ * Used by ultra application to specify their UPID (Ultra Protocol ID).
+ *
+ * Note : currently, we can bind only to LSAP 0x70, which is the spec.
+ * As SAPs 0x71-0x7F are undefined, we could imagine using them as well...
+ *
+ * Note bis : if we were *very* nice, we could provide two ULTRA services,
+ * with SAR and without SAR (by having different protocol number).
+ * I feel that having SAR with Ultra is asking for troubles, so for now
+ * we will leave the responsability of doing SAR in the application.
+ */
+static int irda_bind_ultra(struct socket *sock, struct sockaddr *uaddr,
+ int addr_len)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;
+ struct irda_sock *self;
+ /*__u16 hints = 0; - Is there a hint for ultra ? */
+ int lsap;
+ int upid_b; /* UPID byte */
+ int i;
+ int err;
+
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+ self = sk->protinfo.irda;
+ ASSERT(self != NULL, return -1;);
+
+ if (addr_len != sizeof(struct sockaddr_irda))
+ return -EINVAL;
+
+ /* Special care for non Ultra sockets */
+ if ((sk->type != SOCK_DGRAM) && (sk->protocol != IRDAPROTO_ULTRA))
+ return -ESOCKTNOSUPPORT;
+
+ /* Parse the daddr field to get the bytes and the size */
+ /* Note : should create out own sockaddr_irda structure
+ * replacing daddr (that we don't use) by upid[4].
+ * It would just fit in the same space, which is cool ! */
+ for(i = 0; i < 4; i++) {
+ /* Get one byte */
+ upid_b = (addr->sir_addr >> (8*i)) & 0xFF;
+ self->upid[i] = upid_b;
+
+ /* Check the extended flag */
+ if ((upid_b & 0x80) == 0)
+ break;
+ }
+ self->upid_l = i + 1;
+ /* Check if the fourth byte has the extended flag */
+ if((i == 4) || (i >= ULTRA_HEADER)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), UPID too long!\n");
+ return -EINVAL;
+ }
+
+ /* Create a LDSAP for us in LMP */
+ lsap = 0x70; /* Fixme */
+ err = irda_open_lsap(self, lsap);
+ if (err < 0)
+ return err;
+ /* Set the destination LSAP we target */
+ self->lsap->dlsap_sel = lsap;
+ /* Note : we should set somehow the upid in the lsap so that
+ * IrLMP is able to multiplex for us... */
+
+ /* Set max sizes of the different bits */
+ self->max_data_size = ULTRA_MAX_DATA - self->upid_l;
+ self->max_header_size = IRDA_MAX_HEADER + self->upid_l;
+
+ /* Move to connected state ??? */
+ sock->state = SS_CONNECTED;
+ sk->state = TCP_ESTABLISHED;
+
+ /* Register with LM-IAS - just for fun */
+ self->ias_obj = irias_new_object(addr->sir_name, jiffies);
+ irias_add_integer_attrib(self->ias_obj, "IrDA:Ultra:LsapSel",
+ self->stsap_sel);
+ irias_insert_object(self->ias_obj);
+
+ return 0;
+}
+
+/*
* Function irda_accept (sock, newsock, flags)
*
* Wait for incomming connection
@@ -1351,6 +1424,7 @@ static int irda_sendmsg_ultra(struct soc
struct irda_sock *self;
struct sk_buff *skb;
unsigned char *asmptr;
+ int i;
int err;
IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
@@ -1366,6 +1440,12 @@ static int irda_sendmsg_ultra(struct soc
self = sk->protinfo.irda;
ASSERT(self != NULL, return -1;);
+ /* Check that we have something to send (LMP doesn't) */
+ if (len == 0) {
+ IRDA_DEBUG(1, __FUNCTION__ "(), No data\n");
+ return -1;
+ }
+
/*
* Check that we don't send out to big frames. This is an unreliable
* service, so we have no fragmentation and no coalescence
@@ -1389,8 +1469,9 @@ static int irda_sendmsg_ultra(struct soc
memcpy_fromiovec(asmptr, msg->msg_iov, len);
/* Insert Ultra header */
- skb_push(skb, ULTRA_HEADER);
- skb->data[0] = self->pid;
+ skb_push(skb, self->upid_l);
+ for (i = 0; i < self->upid_l; i++)
+ skb->data[i] = self->upid[i];
err = irlmp_ultra_request(self->lsap, skb);
if (err) {
@@ -1768,7 +1849,7 @@ static struct proto_ops irda_ultra_ops =
sock_no_dup,
irda_release,
- irda_bind,
+ irda_bind_ultra,
sock_no_connect,
sock_no_socketpair,
sock_no_accept,
diff -u -p linux/net/irda/irlap.d1.c linux/net/irda/irlap.c
--- linux/net/irda/irlap.d1.c Wed Dec 8 10:51:37 1999
+++ linux/net/irda/irlap.c Wed Dec 8 14:08:52 1999
@@ -336,6 +336,8 @@ inline void irlap_data_indication(struct
*/
void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
{
+ __u8 *frame = skb->data;
+
IRDA_DEBUG(1, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
@@ -346,7 +348,7 @@ void irlap_unitdata_indication(struct ir
skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
#ifdef CONFIG_IRDA_COMPRESSION
- if (self->qos_tx.compression.value) {
+ if (self->qos_tx.compression.value && (frame[0] != 0xFF)) {
skb = irlap_decompress_frame(self, skb);
if (!skb) {
@@ -395,6 +397,8 @@ void irlap_data_request(struct irlap_cb
IRDA_DEBUG(4, __FUNCTION__ "(), queueing unreliable frame\n");
skb->data[1] = UI_FRAME;
}
+ /* Specify that it is not a broadcast frame, will be set later */
+ skb->data[0] = 0x0;
/*
* Send event if this frame only if we are in the right state
@@ -419,11 +423,27 @@ void irlap_data_request(struct irlap_cb
/*
* Function irlap_udata_request (self, skb)
*
- * Send Ultra data. This is data that must be sent outside any connection
+ * Send Broadcast Frame (for the connectionless SAP).
+ * This is data that must be sent outside any connection
*
+ * Note : rename to irlap_bdata_request or irlap_budata_request
+ * Note : rename SEND_UI_FRAME to SEND_BROADCAST_FRAME
+ * Explanation : UI frame within a connection don't go through here...
*/
void irlap_udata_request(struct irlap_cb *self, struct sk_buff *skb)
{
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+
+ IRDA_DEBUG(3, __FUNCTION__ "()\n");
+
+ ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
+ return;);
+ skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+
+ skb->data[0] = 0xFF; /* Fixme to UIBROADCAST */
+ skb->data[1] = UI_FRAME;
+
skb_queue_tail(&self->txq_ultra, skb);
irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
@@ -434,6 +454,10 @@ void irlap_udata_request(struct irlap_cb
*
* Receive Ultra data. This is data that is received outside any connection
*
+ * Note : rename to irlap_bdata_indication or irlap_budata_indication
+ * Explanation : UI frame within a connection don't go through here...
+ *
+ * Function no longer used...
*/
void irlap_udata_indication(struct irlap_cb *self, struct sk_buff *skb)
{
@@ -442,6 +466,10 @@ void irlap_udata_indication(struct irlap
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
ASSERT(skb != NULL, return;);
+
+ /* Note : in theory, we have already checked in irlap_recv_ui_frame
+ * if it's a braodcast frame, so we don't need to filter out
+ * unicast frames here... */
/* Hide LAP header from IrLMP layer */
skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
diff -u -p linux/net/irda/irlap_event.d1.c linux/net/irda/irlap_event.c
--- linux/net/irda/irlap_event.d1.c Wed Dec 8 12:28:42 1999
+++ linux/net/irda/irlap_event.c Wed Dec 8 14:09:17 1999
@@ -421,7 +421,10 @@ static int irlap_state_ndm(struct irlap_
}
break;
case RECV_UI_FRAME:
- irlap_udata_indication(self, skb);
+ /* We can only receive broadcast frames in disconnected mode */
+ if(skb->data[0] == 0xFF /* Fixme */)
+ irlap_unitdata_indication(self, skb);
+ /*was irlap_udata_indication(self, skb);*/
break;
case RECV_TEST_CMD:
/* Remove test frame header */
diff -u -p linux/net/irda/irlap_frame.d1.c linux/net/irda/irlap_frame.c
--- linux/net/irda/irlap_frame.d1.c Wed Dec 8 12:31:13 1999
+++ linux/net/irda/irlap_frame.c Wed Dec 8 13:15:27 1999
@@ -1000,9 +1000,12 @@ void irlap_send_ui_frame(struct irlap_cb
frame = skb->data;
- /* Insert connection address */
- frame[0] = self->caddr;
- frame[0] |= (command) ? CMD_FRAME : 0;
+ /* Detect broadcast frames - a bit hackish, so what ? */
+ if(frame[0] != 0xFF) {
+ /* Insert connection address */
+ frame[0] = self->caddr;
+ frame[0] |= (command) ? CMD_FRAME : 0;
+ }
irlap_queue_xmit(self, skb);
}
diff -u -p linux/net/irda/irlmp.d1.c linux/net/irda/irlmp.c
--- linux/net/irda/irlmp.d1.c Wed Dec 8 10:43:30 1999
+++ linux/net/irda/irlmp.c Wed Dec 8 12:24:09 1999
@@ -971,8 +971,9 @@ void irlmp_udata_indication(struct lsap_
/*
* Function irlmp_ultra_request (self, skb)
*
- *
+ * Send a frame on the Connectionless SAP (unreliable & broadcast)
*
+ * Note : rename to irlmp_conless_request
*/
int irlmp_ultra_request(struct lsap_cb *self, struct sk_buff *skb)
{
@@ -987,8 +988,9 @@ int irlmp_ultra_request(struct lsap_cb *
ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
skb_push(skb, LMP_HEADER);
- /* Ultra sockets must use 0x70 */
- skb->data[0] = skb->data[1] = 0x70;
+ /* Ultra sockets must use 0x70, but it's all set up */
+ skb->data[0] = self->dlsap_sel;
+ skb->data[1] = self->slsap_sel;
/* Try to send Ultra packets out on all links */
lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
@@ -999,6 +1001,7 @@ int irlmp_ultra_request(struct lsap_cb *
if (!clone_skb)
return -ENOMEM;
+ //irlap_data_request(self->irlap, skb, FALSE);
irlap_udata_request(lap->irlap, clone_skb);
lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
diff -u -p linux/net/irda/irlmp_event.d1.c linux/net/irda/irlmp_event.c
--- linux/net/irda/irlmp_event.d1.c Wed Dec 8 14:14:08 1999
+++ linux/net/irda/irlmp_event.c Wed Dec 8 13:59:27 1999
@@ -444,6 +444,11 @@ static int irlmp_state_disconnected(stru
irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
break;
+ case LM_UDATA_INDICATION:
+ /* In theory, we can arrive here only if this is a
+ * connectionless lsap (used by Ultra) */
+ irlmp_udata_indication(self, skb);
+ break;
default:
IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
irlmp_event[event]);
diff -u -p linux/net/irda/irlmp_frame.d1.c linux/net/irda/irlmp_frame.c
--- linux/net/irda/irlmp_frame.d1.c Wed Dec 8 14:14:08 1999
+++ linux/net/irda/irlmp_frame.c Wed Dec 8 14:10:14 1999
@@ -37,6 +37,12 @@
static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap,
__u8 slsap, int status, hashbin_t *);
+static struct lsap_cb *irlmp_find_ultra_lsap(struct lap_cb *self,
+ __u8 dlsap_sel,
+ __u8 slsap_sel,
+ hashbin_t *queue,
+ __u8 *upid);
+
inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
int expedited, struct sk_buff *skb)
{
@@ -126,10 +132,20 @@ void irlmp_link_data_indication(struct l
if (!lsap)
lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
self->lsaps);
- } else
- lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
- self->lsaps);
-
+ } else {
+ /* Check if we deal with the connectionless SAPs */
+ if(((dlsap_sel & 0x70) == 0x70) &&
+ ((slsap_sel & 0x70) == 0x70))
+ lsap = irlmp_find_ultra_lsap(self,
+ dlsap_sel, slsap_sel,
+ irlmp->unconnected_lsaps,
+ &fp[2]);
+ else
+ lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
+ self->lsaps);
+ }
+
+printk("lsap = %p, 0x%X, 0x%X\n", lsap, slsap_sel, dlsap_sel);
if (lsap == NULL) {
IRDA_DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
IRDA_DEBUG(2, __FUNCTION__
@@ -182,7 +198,7 @@ void irlmp_link_data_indication(struct l
} else if (reliable == LAP_UNRELIABLE) {
/* Optimize and bypass the state machine if possible */
if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
- irlmp_data_indication(lsap, skb);
+ irlmp_udata_indication(lsap, skb);
else
irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
}
@@ -370,6 +386,60 @@ static struct lsap_cb *irlmp_find_lsap(s
irlmp_update_cache(lsap);
#endif
return lsap;
+ }
+ lsap = (struct lsap_cb *) hashbin_get_next(queue);
+ }
+
+ /* Sorry not found! */
+ return NULL;
+}
+
+
+/*
+ * Function irlmp_find_ultra_lsap (self, dlsap_sel, slsap_sel, status, queue)
+ *
+ * Look for the Connectionless SAP that match the UPID desired
+ *
+ */
+static struct lsap_cb *irlmp_find_ultra_lsap(struct lap_cb *self,
+ __u8 dlsap_sel,
+ __u8 slsap_sel,
+ hashbin_t *queue,
+ __u8 *upid)
+{
+ struct lsap_cb *lsap;
+
+ /* Note : should we trash the lsap cache ?
+ * should we have our own lsap cache ? */
+
+ /*
+ * Optimize for the common case. We assume that the last frame
+ * received is in the same connection as the last one, so check in
+ * cache first to avoid the linear search
+ */
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+ if ((irlmp->cache.valid) &&
+ (irlmp->cache.slsap_sel == slsap_sel) &&
+ (irlmp->cache.dlsap_sel == dlsap_sel))
+ {
+ return (irlmp->cache.lsap);
+ }
+#endif
+ lsap = (struct lsap_cb *) hashbin_get_first(queue);
+ while (lsap != NULL) {
+ /*
+ * Check if source LSAP and dest LSAP selectors match.
+ */
+ if ((lsap->slsap_sel == slsap_sel) &&
+ (lsap->dlsap_sel == dlsap_sel))
+ {
+ /* At this point, we should check the upid */
+ if(upid != NULL /* place-holder */) {
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+ irlmp_update_cache(lsap);
+#endif
+ return lsap;
+ }
}
lsap = (struct lsap_cb *) hashbin_get_next(queue);
}