- char *current_ptr;
- struct dlil_demux_desc *desc;
- u_long id_length; /* IN LONGWORDS!!! */
- struct en_desc *ed;
- u_long *bitmask;
- u_long *proto_id;
- int i;
- short total_length;
- u_long block_count;
- u_long *tmp;
-
-
- 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_NOWAIT);
- 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;
-}
-
-
-static
-int ether_shutdown()
-{
- return 0;
-}
-
-
-
-
+ struct en_desc *ed;
+ struct ether_desc_blk_str *desc_blk = (struct ether_desc_blk_str *)ifp->family_cookie;
+ u_int32_t i;
+
+ switch (demux->type) {
+ /* These types are supported */
+ /* Top three are preferred */
+ case DLIL_DESC_ETYPE2:
+ if (demux->datalen != 2) {
+ return EINVAL;
+ }
+ break;
+
+ case DLIL_DESC_SAP:
+ if (demux->datalen != 3) {
+ return EINVAL;
+ }
+ break;
+
+ case DLIL_DESC_SNAP:
+ if (demux->datalen != 5) {
+ return EINVAL;
+ }
+ break;
+
+ default:
+ return ENOTSUP;
+ }
+
+ // Verify a matching descriptor does not exist.
+ if (desc_blk != NULL) {
+ switch (demux->type) {
+ case DLIL_DESC_ETYPE2:
+ for (i = 0; i < desc_blk->n_max_used; i++) {
+ if (desc_blk->block_ptr[i].type == DLIL_DESC_ETYPE2 &&
+ desc_blk->block_ptr[i].data[0] ==
+ *(u_int16_t*)demux->data) {
+ return EADDRINUSE;
+ }
+ }
+ break;
+ case DLIL_DESC_SAP:
+ case DLIL_DESC_SNAP:
+ for (i = 0; i < desc_blk->n_max_used; i++) {
+ if (desc_blk->block_ptr[i].type == demux->type &&
+ bcmp(desc_blk->block_ptr[i].data, demux->data,
+ demux->datalen) == 0) {
+ return EADDRINUSE;
+ }
+ }
+ break;
+ }
+ }
+
+ // Check for case where all of the descriptor blocks are in use
+ if (desc_blk == NULL || desc_blk->n_used == desc_blk->n_count) {
+ struct ether_desc_blk_str *tmp;
+ u_int32_t new_count = ETHER_DESC_BLK_SIZE;
+ u_int32_t new_size;
+ u_int32_t old_size = 0;
+
+ i = 0;
+
+ if (desc_blk) {
+ new_count += desc_blk->n_count;
+ old_size = desc_blk->n_count * sizeof(struct en_desc) + ETHER_DESC_HEADER_SIZE;
+ i = desc_blk->n_used;
+ }
+
+ new_size = new_count * sizeof(struct en_desc) + ETHER_DESC_HEADER_SIZE;
+
+ tmp = _MALLOC(new_size, M_IFADDR, M_WAITOK);
+ if (tmp == 0) {
+ /*
+ * Remove any previous descriptors set in the call.
+ */
+ return ENOMEM;
+ }