- TAILQ_FOREACH(desc, desc_head, next) {
- switch (desc->type)
- {
- case DLIL_DESC_RAW:
- id_length = desc->variants.bitmask.proto_id_length;
- break;
-
- case DLIL_DESC_802_2:
- id_length = 1;
- break;
-
- case DLIL_DESC_802_2_SNAP:
- id_length = 2;
- break;
-
- default:
- return EINVAL;
- }
-
-restart:
- block_count = ether_desc_blk[proto->ifp->family_cookie].n_blocks;
- current_ptr = (char *) ether_desc_blk[proto->ifp->family_cookie].block_ptr;
- ed = (struct en_desc *) current_ptr;
- total_length = ((id_length << 2) * 2) + DB_HEADER_SIZE;
-
- while ((ed->total_len) && (desc_in_bounds(proto->ifp->family_cookie,
- current_ptr, total_length))) {
- if ((ed->dl_tag == 0) && (total_length <= ed->total_len))
- break;
- else
- current_ptr += *(short *)current_ptr;
-
- ed = (struct en_desc *) current_ptr;
- }
-
- if (!desc_in_bounds(proto->ifp->family_cookie, current_ptr, total_length)) {
-
- tmp = _MALLOC((ETHER_DESC_BLK_SIZE * (block_count + 1)),
- M_IFADDR, M_WAITOK);
- if (tmp == 0) {
- /*
- * Remove any previous descriptors set in the call.
- */
- ether_del_proto(proto, dl_tag);
- return ENOMEM;
- }
-
- bzero(tmp, ETHER_DESC_BLK_SIZE * (block_count + 1));
- bcopy(ether_desc_blk[proto->ifp->family_cookie].block_ptr,
- tmp, (ETHER_DESC_BLK_SIZE * block_count));
- FREE(ether_desc_blk[proto->ifp->family_cookie].block_ptr, M_IFADDR);
- ether_desc_blk[proto->ifp->family_cookie].n_blocks = block_count + 1;
- ether_desc_blk[proto->ifp->family_cookie].block_ptr = tmp;
- goto restart;
- }
-
- if (ed->total_len == 0)
- ed->total_len = total_length;
- ed->ethertype = *((u_short *) desc->native_type);
-
- ed->dl_tag = dl_tag;
- ed->proto = proto;
- ed->proto_id_length = id_length;
- ed->ifp = proto->ifp;
-
- switch (desc->type)
- {
- case DLIL_DESC_RAW:
- bcopy(desc->variants.bitmask.proto_id, &ed->proto_id_data[0], (id_length << 2) );
- bcopy(desc->variants.bitmask.proto_id_mask, &ed->proto_id_data[id_length],
- (id_length << 2));
- break;
-
- case DLIL_DESC_802_2:
- ed->proto_id_data[0] = 0;
- bcopy(&desc->variants.desc_802_2, &ed->proto_id_data[0], 3);
- ed->proto_id_data[1] = 0xffffff00;
- break;
-
- case DLIL_DESC_802_2_SNAP:
- /* XXX Add verification of fixed values here */
-
- ed->proto_id_data[0] = 0;
- ed->proto_id_data[1] = 0;
- bcopy(&desc->variants.desc_802_2_SNAP, &ed->proto_id_data[0], 8);
- ed->proto_id_data[2] = 0xffffffff;
- ed->proto_id_data[3] = 0xffffffff;;
- break;
- }
-
- if (id_length) {
- proto_id = (u_long *) &ed->proto_id_data[0];
- bitmask = (u_long *) &ed->proto_id_data[id_length];
- for (i=0; i < (id_length); i++) {
- litmus_mask[i] &= bitmask[i];
- litmus_mask[i] &= proto_id[i];
- }
- if (id_length > litmus_length)
- litmus_length = id_length;
- }
- }
-
- return 0;
+ TAILQ_FOREACH(desc, desc_head, next) {
+ switch (desc->type) {
+ /* These types are supported */
+ /* Top three are preferred */
+ case DLIL_DESC_ETYPE2:
+ if (desc->variants.native_type_length != 2)
+ return EINVAL;
+ break;
+
+ case DLIL_DESC_SAP:
+ if (desc->variants.native_type_length != 3)
+ return EINVAL;
+ break;
+
+ case DLIL_DESC_SNAP:
+ if (desc->variants.native_type_length != 5)
+ return EINVAL;
+ break;
+
+ case DLIL_DESC_802_2:
+ case DLIL_DESC_802_2_SNAP:
+ break;
+
+ case DLIL_DESC_RAW:
+ if (desc->variants.bitmask.proto_id_length == 0)
+ break;
+ /* else fall through, bitmask variant not supported */
+
+ default:
+ ether_del_proto(proto, dl_tag);
+ return EINVAL;
+ }
+
+ restart:
+ ed = ether_desc_blk[proto->ifp->family_cookie].block_ptr;
+
+ /* Find a free entry */
+ for (i = 0; i < ether_desc_blk[proto->ifp->family_cookie].n_count; i++) {
+ if (ed[i].type == 0) {
+ break;
+ }
+ }
+
+ if (i >= ether_desc_blk[proto->ifp->family_cookie].n_count) {
+ u_long new_count = ETHER_DESC_BLK_SIZE +
+ ether_desc_blk[proto->ifp->family_cookie].n_count;
+ tmp = _MALLOC((new_count * (sizeof(*ed))), M_IFADDR, M_WAITOK);
+ if (tmp == 0) {
+ /*
+ * Remove any previous descriptors set in the call.
+ */
+ ether_del_proto(proto, dl_tag);
+ return ENOMEM;
+ }
+
+ bzero(tmp, new_count * sizeof(*ed));
+ bcopy(ether_desc_blk[proto->ifp->family_cookie].block_ptr,
+ tmp, ether_desc_blk[proto->ifp->family_cookie].n_count * sizeof(*ed));
+ FREE(ether_desc_blk[proto->ifp->family_cookie].block_ptr, M_IFADDR);
+ ether_desc_blk[proto->ifp->family_cookie].n_count = new_count;
+ ether_desc_blk[proto->ifp->family_cookie].block_ptr = (struct en_desc*)tmp;
+ }
+
+ /* Bump n_max_used if appropriate */
+ if (i + 1 > ether_desc_blk[proto->ifp->family_cookie].n_max_used) {
+ ether_desc_blk[proto->ifp->family_cookie].n_max_used = i + 1;
+ }
+
+ ed[i].proto = proto;
+ ed[i].data[0] = 0;
+ ed[i].data[1] = 0;
+
+ switch (desc->type) {
+ case DLIL_DESC_RAW:
+ /* 2 byte ethernet raw protocol type is at native_type */
+ /* protocol is not in network byte order */
+ ed[i].type = DLIL_DESC_ETYPE2;
+ ed[i].data[0] = htons(*(u_int16_t*)desc->native_type);
+ break;
+
+ case DLIL_DESC_ETYPE2:
+ /* 2 byte ethernet raw protocol type is at native_type */
+ /* prtocol must be in network byte order */
+ ed[i].type = DLIL_DESC_ETYPE2;
+ ed[i].data[0] = *(u_int16_t*)desc->native_type;
+ break;
+
+ case DLIL_DESC_802_2:
+ ed[i].type = DLIL_DESC_SAP;
+ ed[i].data[0] = *(u_int32_t*)&desc->variants.desc_802_2;
+ ed[i].data[0] &= htonl(0xFFFFFF00);
+ break;
+
+ case DLIL_DESC_SAP:
+ ed[i].type = DLIL_DESC_SAP;
+ bcopy(desc->native_type, &ed[i].data[0], 3);
+ break;
+
+ case DLIL_DESC_802_2_SNAP:
+ ed[i].type = DLIL_DESC_SNAP;
+ desc->variants.desc_802_2_SNAP.protocol_type =
+ htons(desc->variants.desc_802_2_SNAP.protocol_type);
+ bcopy(&desc->variants.desc_802_2_SNAP, &ed[i].data[0], 8);
+ ed[i].data[0] &= htonl(0x000000FF);
+ desc->variants.desc_802_2_SNAP.protocol_type =
+ ntohs(desc->variants.desc_802_2_SNAP.protocol_type);
+ break;
+
+ case DLIL_DESC_SNAP: {
+ u_int8_t* pDest = ((u_int8_t*)&ed[i].data[0]) + 3;
+ ed[i].type = DLIL_DESC_SNAP;
+ bcopy(&desc->native_type, pDest, 5);
+ }
+ break;
+ }
+ }
+
+ return 0;