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, &notify);    
+       self->lsap = irlmp_open_lsap(slsap_sel, &notify);       
        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);
        }

Reply via email to